react-peekaboo
Advanced tools
Comparing version 0.3.0 to 0.4.0
@@ -1,16 +0,8 @@ | ||
import { Component } from 'react'; | ||
import IO from './IO'; | ||
import Scroll from './Scroll'; | ||
import { Props } from './types'; | ||
export { IO, Props, Scroll }; | ||
export declare class InView extends Component<Props> { | ||
static defaultProps: { | ||
enabled: boolean; | ||
offsetBottom: number; | ||
offsetLeft: number; | ||
offsetRight: number; | ||
offsetTop: number; | ||
throttle: number; | ||
}; | ||
render(): import("react").ComponentElement<Props, Scroll> | import("react").ComponentElement<Pick<Props, "enabled" | "children" | "offsetBottom" | "offsetLeft" | "offsetRight" | "offsetTop" | "onChange">, IO>; | ||
} | ||
import { RefCallback } from 'react'; | ||
import { ChangeHandler, Options as PeekabooOptions, SetupHandler } from 'dom-peekaboo'; | ||
export declare type Options = PeekabooOptions & { | ||
enabled?: boolean; | ||
}; | ||
export declare function usePeekaboo<E extends HTMLElement>(setup: SetupHandler, onChange: ChangeHandler, options?: Options): RefCallback<E>; | ||
export declare function useIntersectionChange<E extends HTMLElement>(onChange: ChangeHandler, options?: Options): RefCallback<E>; | ||
export declare function useIntersecting<E extends HTMLElement>(options?: Options): [RefCallback<E>, boolean]; |
@@ -1,288 +0,2 @@ | ||
import _classCallCheck from '@babel/runtime/helpers/esm/classCallCheck'; | ||
import _createClass from '@babel/runtime/helpers/esm/createClass'; | ||
import _possibleConstructorReturn from '@babel/runtime/helpers/esm/possibleConstructorReturn'; | ||
import _getPrototypeOf from '@babel/runtime/helpers/esm/getPrototypeOf'; | ||
import _inherits from '@babel/runtime/helpers/esm/inherits'; | ||
import { Component, createElement } from 'react'; | ||
import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray'; | ||
import throttleFunc from 'lodash.throttle'; | ||
var defaultProps = { | ||
enabled: true, | ||
offsetBottom: 0, | ||
offsetLeft: 0, | ||
offsetRight: 0, | ||
offsetTop: 0, | ||
throttle: 100 | ||
}; | ||
var supported; | ||
function intersectionObserverSupported() { | ||
if (supported === undefined) { | ||
supported = typeof window !== 'undefined' && 'IntersectionObserver' in window; | ||
} | ||
return supported; | ||
} | ||
function io(_ref) { | ||
var element = _ref.element, | ||
offsetBottom = _ref.offsetBottom, | ||
offsetLeft = _ref.offsetLeft, | ||
offsetRight = _ref.offsetRight, | ||
offsetTop = _ref.offsetTop, | ||
onChange = _ref.onChange; | ||
var rootMargin = "".concat(offsetBottom, "px ").concat(offsetLeft, "px ").concat(offsetTop, "px ").concat(offsetRight, "px"); | ||
var observer = new IntersectionObserver(function (_ref2) { | ||
var _ref3 = _slicedToArray(_ref2, 1), | ||
entry = _ref3[0]; | ||
onChange(entry.isIntersecting); | ||
}, { | ||
root: null, | ||
rootMargin: rootMargin | ||
}); | ||
observer.observe(element); | ||
return function () { | ||
observer.unobserve(element); | ||
}; | ||
} | ||
function isElementInDocument(element) { | ||
return 'isConnected' in element ? element.isConnected : document.body.contains(element); | ||
} | ||
function isElementIntersecting(element, _ref4) { | ||
var offsetBottom = _ref4.offsetBottom, | ||
offsetLeft = _ref4.offsetLeft, | ||
offsetRight = _ref4.offsetRight, | ||
offsetTop = _ref4.offsetTop; | ||
if (!isElementInDocument(element)) { | ||
return false; | ||
} | ||
var rect = element.getBoundingClientRect(); | ||
var adjustedBottom = rect.bottom + offsetBottom; | ||
var adjustedLeft = rect.left - offsetLeft; | ||
var adjustedRight = rect.right + offsetRight; | ||
var adjustedTop = rect.top - offsetTop; | ||
return adjustedBottom >= 0 && adjustedLeft <= window.innerWidth && adjustedRight >= 0 && adjustedTop <= window.innerHeight; | ||
} | ||
function scroll(_ref5) { | ||
var element = _ref5.element, | ||
offsetBottom = _ref5.offsetBottom, | ||
offsetLeft = _ref5.offsetLeft, | ||
offsetRight = _ref5.offsetRight, | ||
offsetTop = _ref5.offsetTop, | ||
onChange = _ref5.onChange, | ||
throttle = _ref5.throttle; | ||
var prevInViewport; | ||
var checkViewport = function checkViewport() { | ||
var isInViewport = element ? isElementIntersecting(element, { | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop | ||
}) : false; | ||
if (isInViewport !== prevInViewport) { | ||
prevInViewport = isInViewport; | ||
onChange(isInViewport); | ||
} | ||
}; | ||
var eventHandler = throttleFunc(checkViewport, throttle); | ||
checkViewport(); | ||
window.addEventListener('scroll', eventHandler); | ||
window.addEventListener('resize', eventHandler); | ||
return function () { | ||
window.removeEventListener('scroll', eventHandler); | ||
window.removeEventListener('resize', eventHandler); | ||
}; | ||
} | ||
var IO = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(IO, _Component); | ||
function IO() { | ||
var _this; | ||
_classCallCheck(this, IO); | ||
_this = _possibleConstructorReturn(this, _getPrototypeOf(IO).apply(this, arguments)); | ||
_this.state = { | ||
element: null | ||
}; | ||
_this.childRef = function (element) { | ||
_this.setState({ | ||
element: element | ||
}); | ||
}; | ||
_this.teardown = null; | ||
_this.setup = function () { | ||
if (_this.props.enabled && _this.state.element) { | ||
var _this$props = _this.props, | ||
offsetBottom = _this$props.offsetBottom, | ||
offsetLeft = _this$props.offsetLeft, | ||
offsetRight = _this$props.offsetRight, | ||
offsetTop = _this$props.offsetTop, | ||
onChange = _this$props.onChange; | ||
_this.teardown = io({ | ||
element: _this.state.element, | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop, | ||
onChange: onChange | ||
}); | ||
} | ||
}; | ||
_this.safeTeardown = function () { | ||
if (_this.teardown) { | ||
_this.teardown(); | ||
_this.teardown = null; | ||
} | ||
}; | ||
return _this; | ||
} | ||
_createClass(IO, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
if (prevProps.children !== this.props.children || prevProps.enabled !== this.props.enabled || prevProps.offsetBottom !== this.props.offsetBottom || prevProps.offsetLeft !== this.props.offsetLeft || prevProps.offsetRight !== this.props.offsetRight || prevProps.offsetTop !== this.props.offsetTop || prevProps.onChange !== this.props.onChange || prevState.element !== this.state.element) { | ||
this.safeTeardown(); | ||
this.setup(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.safeTeardown(); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.childRef); | ||
} | ||
}]); | ||
return IO; | ||
}(Component); | ||
IO.defaultProps = defaultProps; | ||
var Scroll = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Scroll, _Component); | ||
function Scroll() { | ||
var _this; | ||
_classCallCheck(this, Scroll); | ||
_this = _possibleConstructorReturn(this, _getPrototypeOf(Scroll).apply(this, arguments)); | ||
_this.state = { | ||
element: null | ||
}; | ||
_this.childRef = function (element) { | ||
_this.setState({ | ||
element: element | ||
}); | ||
}; | ||
_this.teardown = null; | ||
_this.setup = function () { | ||
if (_this.props.enabled && _this.state.element) { | ||
var _this$props = _this.props, | ||
offsetBottom = _this$props.offsetBottom, | ||
offsetLeft = _this$props.offsetLeft, | ||
offsetRight = _this$props.offsetRight, | ||
offsetTop = _this$props.offsetTop, | ||
onChange = _this$props.onChange, | ||
throttle = _this$props.throttle; | ||
_this.teardown = scroll({ | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop, | ||
onChange: onChange, | ||
element: _this.state.element, | ||
throttle: throttle | ||
}); | ||
} | ||
}; | ||
_this.safeTeardown = function () { | ||
if (_this.teardown) { | ||
_this.teardown(); | ||
_this.teardown = null; | ||
} | ||
}; | ||
return _this; | ||
} | ||
_createClass(Scroll, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
if (prevProps.children !== this.props.children || prevProps.enabled !== this.props.enabled || prevProps.offsetBottom !== this.props.offsetBottom || prevProps.offsetLeft !== this.props.offsetLeft || prevProps.offsetRight !== this.props.offsetRight || prevProps.offsetTop !== this.props.offsetTop || prevProps.onChange !== this.props.onChange || prevProps.throttle !== this.props.throttle || prevState.element !== this.state.element) { | ||
this.safeTeardown(); | ||
this.setup(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.safeTeardown(); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.childRef); | ||
} | ||
}]); | ||
return Scroll; | ||
}(Component); | ||
Scroll.defaultProps = defaultProps; | ||
var InView = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(InView, _Component); | ||
function InView() { | ||
_classCallCheck(this, InView); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(InView).apply(this, arguments)); | ||
} | ||
_createClass(InView, [{ | ||
key: "render", | ||
value: function render() { | ||
if (!intersectionObserverSupported()) { | ||
return createElement(Scroll, this.props); | ||
} | ||
return createElement(IO, this.props); | ||
} | ||
}]); | ||
return InView; | ||
}(Component); | ||
InView.defaultProps = defaultProps; | ||
export { IO, InView, Scroll }; | ||
import{useState as r,useEffect as o}from"react";import{peekaboo as n}from"dom-peekaboo";function t(n,t,e){void 0===e&&(e={});var i=r(null),u=i[0],f=i[1];return o(function(){if(u&&!1!==e.enabled)return n(u,t,e)},[u,t,e]),f}function e(r,o){return void 0===o&&(o={}),t(n,r,o)}function i(o){void 0===o&&(o={});var e=r(!1),i=e[0];return[t(n,e[1],o),i]}export{i as useIntersecting,e as useIntersectionChange,t as usePeekaboo}; | ||
//# sourceMappingURL=index.esm.js.map |
@@ -1,296 +0,2 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck')); | ||
var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass')); | ||
var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn')); | ||
var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf')); | ||
var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits')); | ||
var react = require('react'); | ||
var _slicedToArray = _interopDefault(require('@babel/runtime/helpers/slicedToArray')); | ||
var throttleFunc = _interopDefault(require('lodash.throttle')); | ||
var defaultProps = { | ||
enabled: true, | ||
offsetBottom: 0, | ||
offsetLeft: 0, | ||
offsetRight: 0, | ||
offsetTop: 0, | ||
throttle: 100 | ||
}; | ||
var supported; | ||
function intersectionObserverSupported() { | ||
if (supported === undefined) { | ||
supported = typeof window !== 'undefined' && 'IntersectionObserver' in window; | ||
} | ||
return supported; | ||
} | ||
function io(_ref) { | ||
var element = _ref.element, | ||
offsetBottom = _ref.offsetBottom, | ||
offsetLeft = _ref.offsetLeft, | ||
offsetRight = _ref.offsetRight, | ||
offsetTop = _ref.offsetTop, | ||
onChange = _ref.onChange; | ||
var rootMargin = "".concat(offsetBottom, "px ").concat(offsetLeft, "px ").concat(offsetTop, "px ").concat(offsetRight, "px"); | ||
var observer = new IntersectionObserver(function (_ref2) { | ||
var _ref3 = _slicedToArray(_ref2, 1), | ||
entry = _ref3[0]; | ||
onChange(entry.isIntersecting); | ||
}, { | ||
root: null, | ||
rootMargin: rootMargin | ||
}); | ||
observer.observe(element); | ||
return function () { | ||
observer.unobserve(element); | ||
}; | ||
} | ||
function isElementInDocument(element) { | ||
return 'isConnected' in element ? element.isConnected : document.body.contains(element); | ||
} | ||
function isElementIntersecting(element, _ref4) { | ||
var offsetBottom = _ref4.offsetBottom, | ||
offsetLeft = _ref4.offsetLeft, | ||
offsetRight = _ref4.offsetRight, | ||
offsetTop = _ref4.offsetTop; | ||
if (!isElementInDocument(element)) { | ||
return false; | ||
} | ||
var rect = element.getBoundingClientRect(); | ||
var adjustedBottom = rect.bottom + offsetBottom; | ||
var adjustedLeft = rect.left - offsetLeft; | ||
var adjustedRight = rect.right + offsetRight; | ||
var adjustedTop = rect.top - offsetTop; | ||
return adjustedBottom >= 0 && adjustedLeft <= window.innerWidth && adjustedRight >= 0 && adjustedTop <= window.innerHeight; | ||
} | ||
function scroll(_ref5) { | ||
var element = _ref5.element, | ||
offsetBottom = _ref5.offsetBottom, | ||
offsetLeft = _ref5.offsetLeft, | ||
offsetRight = _ref5.offsetRight, | ||
offsetTop = _ref5.offsetTop, | ||
onChange = _ref5.onChange, | ||
throttle = _ref5.throttle; | ||
var prevInViewport; | ||
var checkViewport = function checkViewport() { | ||
var isInViewport = element ? isElementIntersecting(element, { | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop | ||
}) : false; | ||
if (isInViewport !== prevInViewport) { | ||
prevInViewport = isInViewport; | ||
onChange(isInViewport); | ||
} | ||
}; | ||
var eventHandler = throttleFunc(checkViewport, throttle); | ||
checkViewport(); | ||
window.addEventListener('scroll', eventHandler); | ||
window.addEventListener('resize', eventHandler); | ||
return function () { | ||
window.removeEventListener('scroll', eventHandler); | ||
window.removeEventListener('resize', eventHandler); | ||
}; | ||
} | ||
var IO = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(IO, _Component); | ||
function IO() { | ||
var _this; | ||
_classCallCheck(this, IO); | ||
_this = _possibleConstructorReturn(this, _getPrototypeOf(IO).apply(this, arguments)); | ||
_this.state = { | ||
element: null | ||
}; | ||
_this.childRef = function (element) { | ||
_this.setState({ | ||
element: element | ||
}); | ||
}; | ||
_this.teardown = null; | ||
_this.setup = function () { | ||
if (_this.props.enabled && _this.state.element) { | ||
var _this$props = _this.props, | ||
offsetBottom = _this$props.offsetBottom, | ||
offsetLeft = _this$props.offsetLeft, | ||
offsetRight = _this$props.offsetRight, | ||
offsetTop = _this$props.offsetTop, | ||
onChange = _this$props.onChange; | ||
_this.teardown = io({ | ||
element: _this.state.element, | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop, | ||
onChange: onChange | ||
}); | ||
} | ||
}; | ||
_this.safeTeardown = function () { | ||
if (_this.teardown) { | ||
_this.teardown(); | ||
_this.teardown = null; | ||
} | ||
}; | ||
return _this; | ||
} | ||
_createClass(IO, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
if (prevProps.children !== this.props.children || prevProps.enabled !== this.props.enabled || prevProps.offsetBottom !== this.props.offsetBottom || prevProps.offsetLeft !== this.props.offsetLeft || prevProps.offsetRight !== this.props.offsetRight || prevProps.offsetTop !== this.props.offsetTop || prevProps.onChange !== this.props.onChange || prevState.element !== this.state.element) { | ||
this.safeTeardown(); | ||
this.setup(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.safeTeardown(); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.childRef); | ||
} | ||
}]); | ||
return IO; | ||
}(react.Component); | ||
IO.defaultProps = defaultProps; | ||
var Scroll = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Scroll, _Component); | ||
function Scroll() { | ||
var _this; | ||
_classCallCheck(this, Scroll); | ||
_this = _possibleConstructorReturn(this, _getPrototypeOf(Scroll).apply(this, arguments)); | ||
_this.state = { | ||
element: null | ||
}; | ||
_this.childRef = function (element) { | ||
_this.setState({ | ||
element: element | ||
}); | ||
}; | ||
_this.teardown = null; | ||
_this.setup = function () { | ||
if (_this.props.enabled && _this.state.element) { | ||
var _this$props = _this.props, | ||
offsetBottom = _this$props.offsetBottom, | ||
offsetLeft = _this$props.offsetLeft, | ||
offsetRight = _this$props.offsetRight, | ||
offsetTop = _this$props.offsetTop, | ||
onChange = _this$props.onChange, | ||
throttle = _this$props.throttle; | ||
_this.teardown = scroll({ | ||
offsetBottom: offsetBottom, | ||
offsetLeft: offsetLeft, | ||
offsetRight: offsetRight, | ||
offsetTop: offsetTop, | ||
onChange: onChange, | ||
element: _this.state.element, | ||
throttle: throttle | ||
}); | ||
} | ||
}; | ||
_this.safeTeardown = function () { | ||
if (_this.teardown) { | ||
_this.teardown(); | ||
_this.teardown = null; | ||
} | ||
}; | ||
return _this; | ||
} | ||
_createClass(Scroll, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
if (prevProps.children !== this.props.children || prevProps.enabled !== this.props.enabled || prevProps.offsetBottom !== this.props.offsetBottom || prevProps.offsetLeft !== this.props.offsetLeft || prevProps.offsetRight !== this.props.offsetRight || prevProps.offsetTop !== this.props.offsetTop || prevProps.onChange !== this.props.onChange || prevProps.throttle !== this.props.throttle || prevState.element !== this.state.element) { | ||
this.safeTeardown(); | ||
this.setup(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.safeTeardown(); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.childRef); | ||
} | ||
}]); | ||
return Scroll; | ||
}(react.Component); | ||
Scroll.defaultProps = defaultProps; | ||
var InView = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(InView, _Component); | ||
function InView() { | ||
_classCallCheck(this, InView); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(InView).apply(this, arguments)); | ||
} | ||
_createClass(InView, [{ | ||
key: "render", | ||
value: function render() { | ||
if (!intersectionObserverSupported()) { | ||
return react.createElement(Scroll, this.props); | ||
} | ||
return react.createElement(IO, this.props); | ||
} | ||
}]); | ||
return InView; | ||
}(react.Component); | ||
InView.defaultProps = defaultProps; | ||
exports.IO = IO; | ||
exports.InView = InView; | ||
exports.Scroll = Scroll; | ||
var e=require("react"),r=require("dom-peekaboo");function t(r,t,o){void 0===o&&(o={});var n=e.useState(null),u=n[0],a=n[1];return e.useEffect(function(){if(u&&!1!==o.enabled)return r(u,t,o)},[u,t,o]),a}exports.useIntersecting=function(o){void 0===o&&(o={});var n=e.useState(!1),u=n[0];return[t(r.peekaboo,n[1],o),u]},exports.useIntersectionChange=function(e,o){return void 0===o&&(o={}),t(r.peekaboo,e,o)},exports.usePeekaboo=t; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "react-peekaboo", | ||
"description": "React component that notifies when its child enters or exits the viewport", | ||
"version": "0.3.0", | ||
"description": "React hooks for monitoring an element's intersection with the viewport", | ||
"version": "0.4.0", | ||
"license": "MIT", | ||
@@ -31,58 +31,42 @@ "author": "Wyatt Johnston <w@wyatt.page>", | ||
"lint-staged": { | ||
"**/*.{js,jsx,ts,tsx,md}": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
"*.{js,jsx,ts,tsx,md}": "prettier --write" | ||
}, | ||
"scripts": { | ||
"build": "tsc && rollup -c", | ||
"ci": "npm run test:e2e:ci", | ||
"dev": "cross-env NODE_ENV=dev next dev", | ||
"prebuild": "rimraf compiled dist", | ||
"prepublishOnly": "npm run test && npm run build", | ||
"test": "npm run test:e2e", | ||
"test:e2e": "start-server-and-test dev \"http://localhost:3000/list|http://localhost:3000/ref-swap\" test:jest:e2e", | ||
"test:e2e:ci": "start-server-and-test dev \"http://localhost:3000/list|http://localhost:3000/ref-swap\" test:jest:e2e:ci", | ||
"test:jest:e2e": "jest -c jest.config.e2e.js", | ||
"test:jest:e2e:ci": "cross-env CI=true jest -c jest.config.e2e.js --runInBand", | ||
"typecheck": "tsc" | ||
"build": "microbundle build --jsx React.createElement", | ||
"dev": "cross-env NODE_ENV=development next dev", | ||
"prebuild": "rimraf dist", | ||
"test": "jest", | ||
"typecheck": "tsc --noEmit" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.4.0", | ||
"@babel/plugin-proposal-class-properties": "^7.4.0", | ||
"@babel/plugin-transform-runtime": "^7.4.0", | ||
"@babel/preset-env": "^7.4.2", | ||
"@babel/preset-react": "^7.0.0", | ||
"@babel/preset-typescript": "^7.3.3", | ||
"@types/jest": "^24.0.11", | ||
"@babel/core": "^7.11.6", | ||
"@babel/plugin-proposal-class-properties": "^7.10.4", | ||
"@babel/plugin-transform-runtime": "^7.11.5", | ||
"@babel/preset-env": "^7.11.5", | ||
"@babel/preset-react": "^7.10.4", | ||
"@babel/preset-typescript": "^7.10.4", | ||
"@testing-library/jest-dom": "^5.11.4", | ||
"@testing-library/react": "^11.0.2", | ||
"@types/jest": "^26.0.13", | ||
"@types/lodash.throttle": "^4.1.6", | ||
"@types/react": "^16.8.8", | ||
"@types/react-dom": "^16.8.3", | ||
"@zeit/next-typescript": "^1.1.1", | ||
"babel-jest": "^24.5.0", | ||
"cross-env": "^5.2.0", | ||
"husky": "^1.3.1", | ||
"jest": "^24.5.0", | ||
"jest-puppeteer": "^4.1.0", | ||
"lint-staged": "^8.1.5", | ||
"next": "^8.0.3", | ||
"prettier": "^1.16.4", | ||
"puppeteer": "^1.13.0", | ||
"react": "^16.8.5", | ||
"react-dom": "^16.8.5", | ||
"rimraf": "^2.6.3", | ||
"rollup": "^1.7.2", | ||
"rollup-plugin-babel": "^4.3.2", | ||
"rollup-plugin-commonjs": "^9.2.1", | ||
"rollup-plugin-node-resolve": "^4.0.1", | ||
"start-server-and-test": "^1.7.12", | ||
"typescript": "^3.3.4000" | ||
"@types/react": "^16.9.49", | ||
"babel-jest": "^26.3.0", | ||
"cross-env": "^7.0.2", | ||
"husky": "^4.3.0", | ||
"jest": "^26.4.2", | ||
"lint-staged": "^10.3.0", | ||
"microbundle": "^0.12.3", | ||
"prettier": "^2.1.1", | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1", | ||
"rimraf": "^3.0.2", | ||
"typescript": "^4.0.2" | ||
}, | ||
"dependencies": { | ||
"@babel/runtime": "^7.0.0", | ||
"dom-peekaboo": "^0.1.0", | ||
"lodash.throttle": "^4.1.1" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=16" | ||
"react": ">=16.8.0" | ||
} | ||
} |
230
README.md
# `react-peekaboo` | ||
[![Build Status](https://cloud.drone.io/api/badges/wpj/react-peekaboo/status.svg)](https://cloud.drone.io/wpj/react-peekaboo) | ||
[![CI Status](https://github.com/wpj/react-peekaboo/workflows/CI/badge.svg)](https://github.com/wpj/react-peekaboo/actions) | ||
React component that notifies you when its child enters or exits the viewport. | ||
Under the hood, it uses the `IntersectionObserver` API in supported environments | ||
and falls back to listening for `scroll` and `resize` events in combination with | ||
`getBoundingClientRect` in unsupported environments. | ||
React hooks for monitoring an element's intersection with the viewport. | ||
@@ -13,28 +10,27 @@ ## Installation | ||
``` | ||
yarn add react-peekaboo | ||
npm install react-peekaboo | ||
``` | ||
Or | ||
``` | ||
npm install --save react-peekaboo | ||
``` | ||
## Usage | ||
```jsx | ||
```tsx | ||
import React, { useState } from 'react'; | ||
import { InView } from 'react-peekaboo'; | ||
import { useIntersecting, useIntersectionChange } from 'react-peekaboo'; | ||
function Example() { | ||
const [isInViewport, setIsInViewport] = useState(false); | ||
function UseIntersectionExample() { | ||
let [ref, isIntersecting] = useIntersecting<HTMLDivElement>(); | ||
return ( | ||
<InView onChange={setIsInViewport}> | ||
{ref => ( | ||
<div ref={ref}>I am {isInViewport ? 'visible' : 'not visible'}.</div> | ||
)} | ||
</InView> | ||
<div ref={ref}>I am {isIntersecting ? 'visible' : 'not visible'}.</div> | ||
); | ||
} | ||
function UseIntersectionChangeExample() { | ||
let [isIntersecting, onChange] = useState<boolean>(false); | ||
let ref = useIntersectionChange<HTMLDivElement>(onChange); | ||
return ( | ||
<div ref={ref}>I am {isIntersecting ? 'visible' : 'not visible'}.</div> | ||
); | ||
} | ||
``` | ||
@@ -44,166 +40,72 @@ | ||
### `InView` | ||
### Options | ||
#### Props | ||
All functions accept a common set of options: | ||
##### `children: (ref: React.Ref<any>) => JSX.Element` | ||
- `enabled?: boolean`: Enables/disables running the side effect that calculates | ||
the element's intersection status. (default: `true`) | ||
Render prop that accepts a ref as its parameter. You must apply the ref to a DOM | ||
element. | ||
- `offsetBottom?: number`: Number of pixels to add to the bottom of the area | ||
checked against when computing element intersection. (default: `0`) | ||
##### `enabled: boolean` | ||
- `offsetLeft?: number`: Number of pixels to add to the left of the area checked | ||
against when computing element intersection. (default: `0`) | ||
Enables/disables running the viewport-check side effect. | ||
- `offsetRight?: number`: Number of pixels to add to the right of the area | ||
checked against when computing element intersection. (default: `0`) | ||
Default: `true` | ||
- `offsetTop?: number`: Number of pixels to add to the top of the area checked | ||
against when computing element intersection. (default: `0`) | ||
##### `offsetBottom?: number` | ||
- `throttle?: number`: Number of ms to throttle scroll events (only applies in | ||
environments that don't support IntersectionObserver or when using | ||
`useScrollIntersection`/`useScrollIntersectionChangeCallback`). (default: | ||
`100`) | ||
Number of pixels to add to the bottom of the area checked against when computing | ||
in view elements. | ||
### Exports | ||
Default: `0` | ||
#### `useIntersecting` | ||
##### `offsetLeft?: number` | ||
Type: `(options: Options) => [RefCallback, boolean]` | ||
Number of pixels to add to the left of the area checked against when computing | ||
in view elements. | ||
Returns a ref and the element's intersection status using IntersectionObserver | ||
or `scroll`/`resize` event listeners and `getBoundingClientRect` in unsupported | ||
environments. | ||
Default: `0` | ||
The ref returned must be attached to a DOM node. | ||
##### `offsetRight?: number` | ||
#### `useIntersectionChange` | ||
Number of pixels to add to the right of the area checked against when computing | ||
in view elements. | ||
Type: | ||
Default: `0` | ||
```typescript | ||
(onChange: (isIntersecting: boolean) => void, options: Options) => RefCallback; | ||
``` | ||
##### `offsetTop?: number` | ||
Runs a callback that receives the element's intersection status each time it | ||
changes using IntersectionObserver or `scroll`/`resize` event listeners and | ||
`getBoundingClientRect` in unsupported environments. | ||
Number of pixels to add to the top of the area checked against when computing in | ||
view elements. | ||
Returns a ref that must be attached to a DOM node. | ||
Default: `0` | ||
#### `usePeekaboo` | ||
##### `onChange: (isInviewPort: boolean) => void` | ||
Type: | ||
Callback that's invoked each time the wrapped element enters or exits the | ||
viewport. | ||
```typescript | ||
type SetupHandler = ( | ||
element: HTMLElement, | ||
onChange: (isIntersecting: boolean) => void, | ||
options?: Options, | ||
) => TeardownHandler; | ||
##### `throttle?: number` | ||
( | ||
setup: SetupHandler, | ||
onChange: (isIntersecting: boolean) => void, | ||
options?: Options, | ||
) => RefCallback; | ||
``` | ||
Number of ms to throttle scroll events (only applies in environments that don't | ||
support IntersectionObserver). | ||
Default: `100` | ||
### `IO` | ||
#### Props | ||
##### `children: (ref: React.Ref<any>) => JSX.Element` | ||
Render prop that accepts a ref as its parameter. You must apply the ref to a DOM | ||
element. | ||
##### `enabled: boolean` | ||
Enables/disables running the viewport-check side effect. | ||
Default: `true` | ||
##### `offsetBottom?: number` | ||
Number of pixels to add to the bottom of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetLeft?: number` | ||
Number of pixels to add to the left of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetRight?: number` | ||
Number of pixels to add to the right of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetTop?: number` | ||
Number of pixels to add to the top of the area checked against when computing in | ||
view elements. | ||
Default: `0` | ||
##### `onChange: (isInviewPort: boolean) => void` | ||
Callback that's invoked each time the wrapped element enters or exits the | ||
viewport. | ||
### `Scroll` | ||
##### `children: (ref: React.Ref<any>) => JSX.Element` | ||
Render prop that accepts a ref as its parameter. You must apply the ref to a DOM | ||
element. | ||
##### `enabled: boolean` | ||
Enables/disables running the viewport-check side effect. | ||
Default: `true` | ||
##### `offsetBottom?: number` | ||
Number of pixels to add to the bottom of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetLeft?: number` | ||
Number of pixels to add to the left of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetRight?: number` | ||
Number of pixels to add to the right of the area checked against when computing | ||
in view elements. | ||
Default: `0` | ||
##### `offsetTop?: number` | ||
Number of pixels to add to the top of the area checked against when computing in | ||
view elements. | ||
Default: `0` | ||
##### `onChange: (isInviewPort: boolean) => void` | ||
Callback that's invoked each time the wrapped element enters or exits the | ||
viewport. | ||
##### `throttle?: number` | ||
Number of ms to throttle scroll events. | ||
Default: `100` | ||
## Caveats | ||
- This module considers edge-adjacent intersections (when the target element is | ||
directly above/below/beside the viewport) to be in viewport. If you only want | ||
to consider elements with pixels in the viewport as visible, you can configure | ||
`offsetBottom`/`offsetLeft`/`offsetRight`/`offsetTop` to be `-1`. | ||
- IntersectionObserver ignores `rootMargin` in iframe contexts, which means that | ||
offsets will be ignored. | ||
- https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-rootmargin | ||
- https://developers.google.com/web/updates/2016/04/intersectionobserver#iframe_magic | ||
Uses `setup` to run `onChange` when the element's intersection status changes. | ||
You can pass `scroll`, `io`, or `peekaboo` from `dom-peekaboo` or implement our | ||
own setup function. |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
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
22
12
15431
21
4
110
2
+ Addeddom-peekaboo@^0.1.0
+ Addeddom-peekaboo@0.1.0(transitive)
- Removed@babel/runtime@^7.0.0
- Removed@babel/runtime@7.26.0(transitive)
- Removedregenerator-runtime@0.14.1(transitive)