react-detect-offline
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -12,4 +12,6 @@ "use strict"; | ||
var _react2 = _interopRequireDefault(_react); | ||
var _propTypes = require("prop-types"); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -28,11 +30,7 @@ | ||
var config = { | ||
poll: unsupportedUserAgentsPattern.test(navigator.userAgent), | ||
url: "https://ipv4.icanhazip.com/", | ||
timeout: 5000, | ||
interval: 5000 | ||
}; | ||
var ping = function ping(_ref) { | ||
var url = _ref.url, | ||
timeout = _ref.timeout; | ||
var ping = function ping(config) { | ||
return new Promise(function (resolve, reject) { | ||
return new Promise(function (resolve) { | ||
var isOnline = function isOnline() { | ||
@@ -58,4 +56,4 @@ return resolve(true); | ||
xhr.open("GET", config.url); | ||
xhr.timeout = config.url; | ||
xhr.timeout = timeout; | ||
xhr.open("GET", url); | ||
xhr.send(); | ||
@@ -65,2 +63,25 @@ }); | ||
var propTypes = { | ||
children: _propTypes2.default.node, | ||
onChange: _propTypes2.default.func, | ||
polling: _propTypes2.default.oneOfType([_propTypes2.default.shape({ | ||
url: _propTypes2.default.string, | ||
interval: _propTypes2.default.number, | ||
timeout: _propTypes2.default.number | ||
}), _propTypes2.default.bool]), | ||
wrapperType: _propTypes2.default.string | ||
}; | ||
var defaultProps = { | ||
polling: true, | ||
wrapperType: "span" | ||
}; | ||
var defaultPollingConfig = { | ||
enabled: unsupportedUserAgentsPattern.test(navigator.userAgent), | ||
url: "https://ipv4.icanhazip.com/", | ||
timeout: 5000, | ||
interval: 5000 | ||
}; | ||
// base class that detects offline/online changes | ||
@@ -86,11 +107,31 @@ | ||
_createClass(Base, [{ | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
window.addEventListener("online", this.goOnline); | ||
window.addEventListener("offline", this.goOffline); | ||
if (this.getPollingConfig().enabled) { | ||
this.startPolling(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
window.removeEventListener("online", this.goOnline); | ||
window.removeEventListener("offline", this.goOffline); | ||
if (this.pollingId) { | ||
this.stopPolling(); | ||
} | ||
} | ||
}, { | ||
key: "renderChildren", | ||
value: function renderChildren() { | ||
var children = this.props.children; | ||
var _props$wrapperType = this.props.wrapperType, | ||
wrapperType = _props$wrapperType === undefined ? "span" : _props$wrapperType; | ||
var _props = this.props, | ||
children = _props.children, | ||
wrapperType = _props.wrapperType; | ||
// usual case: one child that is a react Element | ||
if (_react2.default.isValidElement(children)) { | ||
if ((0, _react.isValidElement)(children)) { | ||
return children; | ||
@@ -105,8 +146,17 @@ } | ||
// string children, multiple children, or something else | ||
var childrenArray = _react.Children.toArray(children); | ||
var firstChild = childrenArray[0]; | ||
return _react.createElement.apply(undefined, [wrapperType, {}].concat(_toConsumableArray(childrenArray))); | ||
return _react.createElement.apply(undefined, [wrapperType, {}].concat(_toConsumableArray(_react.Children.toArray(children)))); | ||
} | ||
}, { | ||
key: "getPollingConfig", | ||
value: function getPollingConfig() { | ||
switch (this.props.polling) { | ||
case true: | ||
return defaultPollingConfig; | ||
case false: | ||
return { enabled: false }; | ||
default: | ||
return Object.assign({}, defaultPollingConfig, this.props.polling); | ||
} | ||
} | ||
}, { | ||
key: "goOnline", | ||
@@ -139,7 +189,14 @@ value: function goOnline() { | ||
var _getPollingConfig = this.getPollingConfig(), | ||
interval = _getPollingConfig.interval; | ||
this.pollingId = setInterval(function () { | ||
ping(config).then(function (online) { | ||
var _getPollingConfig2 = _this2.getPollingConfig(), | ||
url = _getPollingConfig2.url, | ||
timeout = _getPollingConfig2.timeout; | ||
ping({ url: url, timeout: timeout }).then(function (online) { | ||
online ? _this2.goOnline() : _this2.goOffline(); | ||
}); | ||
}, config.interval); | ||
}, interval); | ||
} | ||
@@ -151,22 +208,2 @@ }, { | ||
} | ||
}, { | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
window.addEventListener("online", this.goOnline); | ||
window.addEventListener("offline", this.goOffline); | ||
if (config.poll) { | ||
this.startPolling(); | ||
} | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
window.removeEventListener("online", this.goOnline); | ||
window.removeEventListener("offline", this.goOffline); | ||
if (config.poll) { | ||
this.stopPolling(); | ||
} | ||
} | ||
}]); | ||
@@ -177,2 +214,5 @@ | ||
Base.propTypes = propTypes; | ||
Base.defaultProps = defaultProps; | ||
var Online = exports.Online = function (_Base) { | ||
@@ -197,2 +237,5 @@ _inherits(Online, _Base); | ||
Online.propTypes = propTypes; | ||
Online.defaultProps = defaultProps; | ||
var Offline = exports.Offline = function (_Base2) { | ||
@@ -217,2 +260,5 @@ _inherits(Offline, _Base2); | ||
Offline.propTypes = propTypes; | ||
Offline.defaultProps = defaultProps; | ||
var Detector = exports.Detector = function (_Base3) { | ||
@@ -236,1 +282,6 @@ _inherits(Detector, _Base3); | ||
}(Base); | ||
Detector.propTypes = Object.assign({}, propTypes, { | ||
render: _propTypes2.default.func.isRequired | ||
}); | ||
Detector.defaultProps = defaultProps; |
{ | ||
"name": "react-detect-offline", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"description": "Offline and Online components for React", | ||
@@ -14,2 +14,3 @@ "main": "dist/index.js", | ||
"babel-cli": "^6.24.1", | ||
"babel-eslint": "^8.2.2", | ||
"babel-jest": "^21.0.0", | ||
@@ -20,3 +21,12 @@ "babel-preset-es2015": "^6.24.1", | ||
"enzyme-to-json": "^1.5.1", | ||
"eslint": "^4.19.1", | ||
"eslint-config-formidable": "^3.0.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-plugin-filenames": "^1.2.0", | ||
"eslint-plugin-import": "^2.9.0", | ||
"eslint-plugin-prettier": "^2.6.0", | ||
"eslint-plugin-react": "^7.7.0", | ||
"jest": "^21.0.1", | ||
"prettier": "^1.11.1", | ||
"prop-types": "^15.6.1", | ||
"react": "^15.6.1", | ||
@@ -31,4 +41,6 @@ "react-dom": "^15.6.1", | ||
"scripts": { | ||
"compile": "babel src/index.js -o dist/index.js", | ||
"build": "babel src/index.js -o dist/index.js", | ||
"test": "jest spec --watch", | ||
"lint": "eslint src/ demo/src", | ||
"prettier": "prettier src/** demo/src/** --write", | ||
"test.cover": "jest spec --coverage" | ||
@@ -35,0 +47,0 @@ }, |
@@ -11,3 +11,3 @@ [![npm](https://img.shields.io/npm/v/react-detect-offline.svg)](https://www.npmjs.com/package/react-detect-offline) | ||
```jsx | ||
import { Offline, Online } from 'react-detect-offline'; | ||
import { Offline, Online } from "react-detect-offline"; | ||
@@ -24,21 +24,35 @@ const App = () => ( | ||
Check out [chris.bolin.co/offline](https://chris.bolin.co/offline) for a simple example ([source code](https://github.com/chrisbolin/offline/blob/master/src/App.js)). As in this example, `react-detect-offline` pairs well with [`create-react-app`](https://github.com/facebookincubator/create-react-app), which creates offline-ready React apps out of the box. | ||
Check out [chris.bolin.co/offline](https://chris.bolin.co/offline) for a simple example ([source code](https://github.com/chrisbolin/offline/blob/master/src/App.js)). | ||
### API | ||
### Components | ||
`<Online/>` - Component that renders its children only when the browser is online. | ||
`<Online/>` - Component that renders its children only when the browser is online. _Recommended for simple use cases._ | ||
`<Offline/>` - Component that renders its children only when the browser is not online. | ||
`<Offline/>` - Component that renders its children only when the browser is not online. _Recommended for simple use cases._ | ||
**Note:** `Online` and `Offline` are mutually exclusive; if one is rendering, the other will not be. | ||
`<Detector render={({ online }) => ...}/>` - Component that calls its `render` prop every time the connection state changes. The `render` prop is supplied with an object with an `online` boolean value. _Recommended for more complex cases, e.g. when styles need to be changed with connection status._ | ||
### Browser Support | ||
### Props | ||
The [web spec](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) we rely on is supported by IE 9+, Chrome 14+, Firefox 41+, and Safari 5+ - that's [94% of worldwide (98% of US)](http://caniuse.com/#feat=online-status) browser traffic. | ||
`<Online/>`, `<Offline/>`, and `<Detector/>` accept the following props: | ||
### Example Uses | ||
| Prop | Type | Description | Default | | ||
| ------------------ | ----------- | --------------------------------- | ------------------------------ | | ||
| `polling` | Obj or Bool | Config for polling fallback [1] | [see below] | | ||
| `polling.enabled` | Boolean | Force polling on or off | Depends on the browser [1] | | ||
| `polling.url` | String | URL to pool for connection status | `"https://ipv4.icanhazip.com"` | | ||
| `polling.interval` | Number | How often (in ms) to poll | `5000` | | ||
| `polling.timeout` | Number | How long (in ms) before timeout | `5000` | | ||
| `onChange` | Function | Called when connection changes | none | | ||
| `children` [2] | Element(s) | Children **not Detector** | none | | ||
| `render` [3] | Func | Render function **Detector only** | none | | ||
- Use `Offline` to remind users they might need to connect to complete certain actions. | ||
- Use `Online` to let readers know the page is available offline. | ||
- Use `Online` to hide links or other content that is irrelevant when offline. | ||
- idk, use your dang imagination. | ||
[1] Polling is only used as a fallback for browsers that don't support the `"online"` event. Currently these are Chrome on Windows, Firefox on Windows, and Chrome on Linux. | ||
[2] `<Online/>` and `<Offline/>` only. `<Detector/>` will not render `children`. | ||
[3] `<Detector/>` only | ||
### Browser Support | ||
The [web spec](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) we rely on is supported by IE 9+, Chrome 14+, Firefox 41+, and Safari 5+ - that's [94% of worldwide (98% of US)](http://caniuse.com/#feat=online-status) browser traffic. A polling fallback is used for browsers that don't implement the spec in a useful way (see note [1] in the above Props section). |
120
src/index.js
@@ -1,7 +0,3 @@ | ||
import React, { | ||
Component, | ||
isValidElement, | ||
Children, | ||
createElement | ||
} from "react"; | ||
import { Component, isValidElement, Children, createElement } from "react"; | ||
import PropTypes from "prop-types"; | ||
@@ -11,11 +7,4 @@ // these browsers don't fully support navigator.onLine, so we need to use a polling backup | ||
const config = { | ||
poll: unsupportedUserAgentsPattern.test(navigator.userAgent), | ||
url: "https://ipv4.icanhazip.com/", | ||
timeout: 5000, | ||
interval: 5000 | ||
}; | ||
const ping = config => { | ||
return new Promise((resolve, reject) => { | ||
const ping = ({ url, timeout }) => { | ||
return new Promise(resolve => { | ||
const isOnline = () => resolve(true); | ||
@@ -37,4 +26,4 @@ const isOffline = () => resolve(false); | ||
xhr.open("GET", config.url); | ||
xhr.timeout = config.url; | ||
xhr.timeout = timeout; | ||
xhr.open("GET", url); | ||
xhr.send(); | ||
@@ -44,2 +33,28 @@ }); | ||
const propTypes = { | ||
children: PropTypes.node, | ||
onChange: PropTypes.func, | ||
polling: PropTypes.oneOfType([ | ||
PropTypes.shape({ | ||
url: PropTypes.string, | ||
interval: PropTypes.number, | ||
timeout: PropTypes.number | ||
}), | ||
PropTypes.bool | ||
]), | ||
wrapperType: PropTypes.string | ||
}; | ||
const defaultProps = { | ||
polling: true, | ||
wrapperType: "span" | ||
}; | ||
const defaultPollingConfig = { | ||
enabled: unsupportedUserAgentsPattern.test(navigator.userAgent), | ||
url: "https://ipv4.icanhazip.com/", | ||
timeout: 5000, | ||
interval: 5000 | ||
}; | ||
// base class that detects offline/online changes | ||
@@ -57,8 +72,25 @@ class Base extends Component { | ||
componentDidMount() { | ||
window.addEventListener("online", this.goOnline); | ||
window.addEventListener("offline", this.goOffline); | ||
if (this.getPollingConfig().enabled) { | ||
this.startPolling(); | ||
} | ||
} | ||
componentWillUnmount() { | ||
window.removeEventListener("online", this.goOnline); | ||
window.removeEventListener("offline", this.goOffline); | ||
if (this.pollingId) { | ||
this.stopPolling(); | ||
} | ||
} | ||
renderChildren() { | ||
const { children } = this.props; | ||
const { wrapperType = "span" } = this.props; | ||
const { children, wrapperType } = this.props; | ||
// usual case: one child that is a react Element | ||
if (React.isValidElement(children)) { | ||
if (isValidElement(children)) { | ||
return children; | ||
@@ -73,6 +105,14 @@ } | ||
// string children, multiple children, or something else | ||
const childrenArray = Children.toArray(children); | ||
const firstChild = childrenArray[0]; | ||
return createElement(wrapperType, {}, ...Children.toArray(children)); | ||
} | ||
return createElement(wrapperType, {}, ...childrenArray); | ||
getPollingConfig() { | ||
switch (this.props.polling) { | ||
case true: | ||
return defaultPollingConfig; | ||
case false: | ||
return { enabled: false }; | ||
default: | ||
return Object.assign({}, defaultPollingConfig, this.props.polling); | ||
} | ||
} | ||
@@ -101,7 +141,9 @@ | ||
startPolling() { | ||
const { interval } = this.getPollingConfig(); | ||
this.pollingId = setInterval(() => { | ||
ping(config).then(online => { | ||
const { url, timeout } = this.getPollingConfig(); | ||
ping({ url, timeout }).then(online => { | ||
online ? this.goOnline() : this.goOffline(); | ||
}); | ||
}, config.interval); | ||
}, interval); | ||
} | ||
@@ -112,21 +154,5 @@ | ||
} | ||
componentDidMount() { | ||
window.addEventListener("online", this.goOnline); | ||
window.addEventListener("offline", this.goOffline); | ||
if (config.poll) { | ||
this.startPolling(); | ||
} | ||
} | ||
componentWillUnmount() { | ||
window.removeEventListener("online", this.goOnline); | ||
window.removeEventListener("offline", this.goOffline); | ||
if (config.poll) { | ||
this.stopPolling(); | ||
} | ||
} | ||
} | ||
Base.propTypes = propTypes; | ||
Base.defaultProps = defaultProps; | ||
@@ -138,2 +164,4 @@ export class Online extends Base { | ||
} | ||
Online.propTypes = propTypes; | ||
Online.defaultProps = defaultProps; | ||
@@ -145,2 +173,4 @@ export class Offline extends Base { | ||
} | ||
Offline.propTypes = propTypes; | ||
Offline.defaultProps = defaultProps; | ||
@@ -152,1 +182,5 @@ export class Detector extends Base { | ||
} | ||
Detector.propTypes = Object.assign({}, propTypes, { | ||
render: PropTypes.func.isRequired | ||
}); | ||
Detector.defaultProps = defaultProps; |
@@ -34,2 +34,12 @@ import React from "react"; | ||
it("should render children when online and using a custom polling URL", () => { | ||
const wrapper = mount( | ||
<Online pollingUrl="https://www.google.com/"> | ||
<h1>Hello World</h1> | ||
</Online> | ||
); | ||
expect(toJSON(wrapper)).toMatchSnapshot(); | ||
}); | ||
it("should not render children when offline", () => { | ||
@@ -47,2 +57,14 @@ Object.defineProperty(navigator, "onLine", { value: false }); | ||
it("should not render children when offline and using a custom polling URL", () => { | ||
Object.defineProperty(navigator, "onLine", { value: false }); | ||
const wrapper = mount( | ||
<Online pollingUrl="https://www.google.com/"> | ||
<h1>Hello World</h1> | ||
</Online> | ||
); | ||
expect(wrapper.html()).toBeNull(); | ||
}); | ||
it("should not render children when going from online to offline", () => { | ||
@@ -91,2 +113,12 @@ const wrapper = mount( | ||
it("should render children when offline and using a custom polling URL", () => { | ||
const wrapper = mount( | ||
<Offline polling={{ url: "https://www.google.com/" }}> | ||
<h1>Hello World</h1> | ||
</Offline> | ||
); | ||
expect(toJSON(wrapper)).toMatchSnapshot(); | ||
}); | ||
it("should not render children when online", () => { | ||
@@ -104,2 +136,14 @@ Object.defineProperty(navigator, "onLine", { value: true }); | ||
it("should not render children when online and using a custom polling URL", () => { | ||
Object.defineProperty(navigator, "onLine", { value: true }); | ||
const wrapper = mount( | ||
<Offline polling={{ url: "https://www.google.com/" }}> | ||
<h1>Hello World</h1> | ||
</Offline> | ||
); | ||
expect(wrapper.html()).toBeNull(); | ||
}); | ||
it("should not render children when going from offline to online", () => { | ||
@@ -106,0 +150,0 @@ const wrapper = mount( |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
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
223383
21
984
57
0
20