├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .travis.yml ├── README.md ├── dist ├── index.es.js ├── index.es.js.map ├── index.js └── index.js.map ├── example ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── ship.sh ├── src │ ├── App.js │ ├── index.css │ └── index.js ├── yarn-error.log └── yarn.lock ├── imgs └── intro.png ├── package.json ├── rollup.config.js ├── src ├── .eslintrc ├── Favicons │ ├── Donut.js │ ├── Exception.js │ ├── Pie.js │ └── Success.js ├── index.js ├── styles.css ├── test.js └── utils │ ├── NoSSR.js │ └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-0", 7 | "react" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react" 6 | ], 7 | "env": { 8 | "es6": true 9 | }, 10 | "plugins": [ 11 | "react" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | // don't force es6 functions to include space before paren 18 | "space-before-function-paren": 0, 19 | 20 | // allow specifying true explicitly for boolean props 21 | "react/jsx-boolean-value": 0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | build/ 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 9 4 | - 8 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-loadcon 2 | 3 | > React component to manipulate the favicon, as a loading or progress indicator, for now. The idea of "Favicon as DOM" is under construction. 4 | 5 | [![NPM](https://img.shields.io/npm/v/react-loadcon.svg)](https://www.npmjs.com/package/react-loadcon) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 6 | 7 | ![](imgs/intro.png) 8 | 9 | ## Why bother? 10 | 11 | When it comes to a huge file loading or download in a tab, a tiny progress indicator on favicon could be an interesting but also considerate UX experience. The idea comes from a long time ago and has been realized by so many open-source developers, and it comes back to me when try to solve this [good first issue](https://github.com/mozilla/send/issues/803) for the Mozilla Send. 12 | 13 | So here is React-LoadCon for React community, now this tiny project can only use canvas to draw dynamic images and replace the tag, which is extremely tedious, but it plans to be a more general tool to offer `Favicon as DOM`. [dom-to-img](https://github.com/tsayen/dom-to-image) could be introduced to simplify the covert process. 14 | 15 | [Live Demo Here](https://foreseaz.github.io/react-loadcon/) 16 | 17 | And if you find the idea interesting, [![Join the favicon community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/favicon) 18 | 19 | 20 | ## 🚀 Installation 21 | 22 | ```bash 23 | npm install --save react-loadcon 24 | ``` 25 | or 26 | ```bash 27 | yarn add react-loadcon 28 | ``` 29 | 30 | ## 🖲 Usage 31 | 32 | Put `` anywhere, even in your SSR components (LoadCon would only trigger after `componentDidMount`). 33 | 34 | ```JavaScript 35 | 36 | ``` 37 | 38 | Full example with async function, and show `Success` or `Exception` afterwards. 39 | 40 | ```JavaScript 41 | import React, { Component } from 'react' 42 | import LoadCon from 'react-loadcon' 43 | 44 | export default class ExampleComponent extends Component { 45 | state = { 46 | percentage: 0, // isRequired 47 | status: 'normal', // oneOf(['normal', 'active', 'exception', 'success']) 48 | type: 'pie', // oneOf(['pie', 'donut']) 49 | } 50 | 51 | componentDidMount () { 52 | this.apiCall() 53 | } 54 | 55 | apiCall = () => { 56 | this.setState({ status: 'active' }) 57 | fetch(url) 58 | .then(res => return res.json()) 59 | .then(data => { 60 | // normal loading 61 | this.setState({ status: 'normal' }) 62 | 63 | // loading with success 64 | this.setState({ status: 'success' }) 65 | setTimeout(() => { 66 | this.setState({ status: 'normal' }) 67 | }, 1500) 68 | }) 69 | .catch(e => { 70 | this.setState({ status: 'exception' }) 71 | setTimeout(() => { 72 | this.setState({ status: 'normal' }) 73 | }, 1500) 74 | }) 75 | } 76 | 77 | render () { 78 | return ( 79 | 84 | ) 85 | } 86 | } 87 | ``` 88 | 89 | ## 🧬 Props 90 | 91 | OPTION | TYPE | DEFAULT | DESCRIPTION 92 | ------ | ---- | ------- | ----------- 93 | percentage | `number` | `0` | the percentage of loading progress for LoadCon 94 | type | `oneOf(['pie', 'donut'])` | `pie` | the theme of LoadCon, now has `PieCon` and `DonutCon`, and more themes will be added soon 95 | status | `oneOf(['normal', 'active', 'exception', 'success'])` | `normal` | load status of LoadCon, `normal` reset to default favicon, `active` set LoadCon according to the type prop, `exception` set ErrorCon and `success` set SuccessCon. 96 | color | `string` | ![](https://placehold.it/15/25c639/000000?text=+) `#25c639` | color of loading indicator in hash format. 97 | background | `string` | ![](https://placehold.it/15/eee/000000?text=+) `#eee` | color of background in hash format. 98 | shadow | `string` | ![](https://placehold.it/15/fff/000000?text=+) `#fff` | color of 2 pixals border in hash format 99 | donutWidth | `number` | `8` | width of DonutCon indicator. 100 | 101 | 102 | ## 📝 License 103 | 104 | MIT © [foreseaz](https://github.com/foreseaz) 105 | -------------------------------------------------------------------------------- /dist/index.es.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | var isArray = Array.isArray; 5 | var keyList = Object.keys; 6 | var hasProp = Object.prototype.hasOwnProperty; 7 | var hasElementType = typeof Element !== 'undefined'; 8 | 9 | function equal(a, b) { 10 | // fast-deep-equal index.js 2.0.1 11 | if (a === b) return true; 12 | 13 | if (a && b && typeof a == 'object' && typeof b == 'object') { 14 | var arrA = isArray(a) 15 | , arrB = isArray(b) 16 | , i 17 | , length 18 | , key; 19 | 20 | if (arrA && arrB) { 21 | length = a.length; 22 | if (length != b.length) return false; 23 | for (i = length; i-- !== 0;) 24 | if (!equal(a[i], b[i])) return false; 25 | return true; 26 | } 27 | 28 | if (arrA != arrB) return false; 29 | 30 | var dateA = a instanceof Date 31 | , dateB = b instanceof Date; 32 | if (dateA != dateB) return false; 33 | if (dateA && dateB) return a.getTime() == b.getTime(); 34 | 35 | var regexpA = a instanceof RegExp 36 | , regexpB = b instanceof RegExp; 37 | if (regexpA != regexpB) return false; 38 | if (regexpA && regexpB) return a.toString() == b.toString(); 39 | 40 | var keys = keyList(a); 41 | length = keys.length; 42 | 43 | if (length !== keyList(b).length) 44 | return false; 45 | 46 | for (i = length; i-- !== 0;) 47 | if (!hasProp.call(b, keys[i])) return false; 48 | // end fast-deep-equal 49 | 50 | // start react-fast-compare 51 | // custom handling for DOM elements 52 | if (hasElementType && a instanceof Element && b instanceof Element) 53 | return a === b; 54 | 55 | // custom handling for React 56 | for (i = length; i-- !== 0;) { 57 | key = keys[i]; 58 | if (key === '_owner' && a.$$typeof) { 59 | // React-specific: avoid traversing React elements' _owner. 60 | // _owner contains circular references 61 | // and is not needed when comparing the actual elements (and not their owners) 62 | // .$$typeof and ._store on just reasonable markers of a react element 63 | continue; 64 | } else { 65 | // all other properties should be traversed as usual 66 | if (!equal(a[key], b[key])) return false; 67 | } 68 | } 69 | // end react-fast-compare 70 | 71 | // fast-deep-equal index.js 2.0.1 72 | return true; 73 | } 74 | 75 | return a !== a && b !== b; 76 | } 77 | // end fast-deep-equal 78 | 79 | var reactFastCompare = function exportedEqual(a, b) { 80 | try { 81 | return equal(a, b); 82 | } catch (error) { 83 | if ((error.message && error.message.match(/stack|recursion/i)) || (error.number === -2146828260)) { 84 | // warn on circular references, don't crash 85 | // browsers give this different errors name and messages: 86 | // chrome/safari: "RangeError", "Maximum call stack size exceeded" 87 | // firefox: "InternalError", too much recursion" 88 | // edge: "Error", "Out of stack space" 89 | console.warn('Warning: react-fast-compare does not handle circular references.', error.name, error.message); 90 | return false; 91 | } 92 | // some other error. we should definitely know about these 93 | throw error; 94 | } 95 | }; 96 | 97 | var classCallCheck = function (instance, Constructor) { 98 | if (!(instance instanceof Constructor)) { 99 | throw new TypeError("Cannot call a class as a function"); 100 | } 101 | }; 102 | 103 | var createClass = function () { 104 | function defineProperties(target, props) { 105 | for (var i = 0; i < props.length; i++) { 106 | var descriptor = props[i]; 107 | descriptor.enumerable = descriptor.enumerable || false; 108 | descriptor.configurable = true; 109 | if ("value" in descriptor) descriptor.writable = true; 110 | Object.defineProperty(target, descriptor.key, descriptor); 111 | } 112 | } 113 | 114 | return function (Constructor, protoProps, staticProps) { 115 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 116 | if (staticProps) defineProperties(Constructor, staticProps); 117 | return Constructor; 118 | }; 119 | }(); 120 | 121 | var inherits = function (subClass, superClass) { 122 | if (typeof superClass !== "function" && superClass !== null) { 123 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 124 | } 125 | 126 | subClass.prototype = Object.create(superClass && superClass.prototype, { 127 | constructor: { 128 | value: subClass, 129 | enumerable: false, 130 | writable: true, 131 | configurable: true 132 | } 133 | }); 134 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 135 | }; 136 | 137 | var possibleConstructorReturn = function (self, call) { 138 | if (!self) { 139 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 140 | } 141 | 142 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 143 | }; 144 | 145 | var DefaultOnSSR = function DefaultOnSSR() { 146 | return React.createElement('span', null); 147 | }; 148 | 149 | var NoSSR = function (_Component) { 150 | inherits(NoSSR, _Component); 151 | 152 | function NoSSR() { 153 | var _ref; 154 | 155 | var _temp, _this, _ret; 156 | 157 | classCallCheck(this, NoSSR); 158 | 159 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 160 | args[_key] = arguments[_key]; 161 | } 162 | 163 | return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = NoSSR.__proto__ || Object.getPrototypeOf(NoSSR)).call.apply(_ref, [this].concat(args))), _this), _this.state = { 164 | canRender: false 165 | }, _temp), possibleConstructorReturn(_this, _ret); 166 | } 167 | 168 | createClass(NoSSR, [{ 169 | key: 'componentDidMount', 170 | value: function componentDidMount() { 171 | this.setState({ canRender: true }); 172 | } 173 | }, { 174 | key: 'render', 175 | value: function render() { 176 | var _props = this.props, 177 | children = _props.children, 178 | _props$onSSR = _props.onSSR, 179 | onSSR = _props$onSSR === undefined ? React.createElement(DefaultOnSSR, null) : _props$onSSR; 180 | 181 | 182 | return React.createElement( 183 | React.Fragment, 184 | null, 185 | this.state.canRender ? children : onSSR 186 | ); 187 | } 188 | }]); 189 | return NoSSR; 190 | }(Component); 191 | 192 | var getIsRetina = function getIsRetina() { 193 | return window.devicePixelRatio > 1; 194 | }; 195 | 196 | var getFaviconURL = function getFaviconURL() { 197 | var links = document.getElementsByTagName('link'); 198 | var tag = null; 199 | 200 | for (var i = 0, l = links.length; i < l; i++) { 201 | if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') { 202 | tag = links[i]; 203 | } 204 | } 205 | 206 | return tag ? tag.getAttribute('href') : '/favicon.ico'; 207 | }; 208 | 209 | var removeFaviconTag = function removeFaviconTag() { 210 | var links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0); 211 | var head = document.getElementsByTagName('head')[0]; 212 | 213 | for (var i = 0, l = links.length; i < l; i++) { 214 | if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') { 215 | head.removeChild(links[i]); 216 | } 217 | } 218 | }; 219 | 220 | var setFaviconTag = function setFaviconTag(url) { 221 | removeFaviconTag(); 222 | 223 | var link = document.createElement('link'); 224 | link.type = 'image/x-icon'; 225 | link.rel = 'icon'; 226 | link.href = url; 227 | 228 | document.getElementsByTagName('head')[0].appendChild(link); 229 | }; 230 | 231 | var getCanvas = function getCanvas() { 232 | var canvas = document.createElement("canvas"); 233 | if (getIsRetina()) { 234 | canvas.width = 32; 235 | canvas.height = 32; 236 | } else { 237 | canvas.width = 16; 238 | canvas.height = 16; 239 | } 240 | 241 | return canvas; 242 | }; 243 | 244 | var Pie = function (_React$Component) { 245 | inherits(Pie, _React$Component); 246 | 247 | function Pie() { 248 | classCallCheck(this, Pie); 249 | return possibleConstructorReturn(this, (Pie.__proto__ || Object.getPrototypeOf(Pie)).apply(this, arguments)); 250 | } 251 | 252 | createClass(Pie, [{ 253 | key: 'componentDidMount', 254 | value: function componentDidMount() { 255 | this.drawFavicon(); 256 | } 257 | }, { 258 | key: 'componentDidUpdate', 259 | value: function componentDidUpdate(prevProps) { 260 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 261 | if (isPropsChanged) { 262 | this.drawFavicon(); 263 | } 264 | } 265 | }, { 266 | key: 'drawFavicon', 267 | value: function drawFavicon() { 268 | var _props = this.props, 269 | percentage = _props.percentage, 270 | color = _props.color, 271 | background = _props.background, 272 | shadow = _props.shadow; 273 | 274 | var canvas = getCanvas(); 275 | var ctx = canvas.getContext('2d'); 276 | 277 | if (ctx) { 278 | ctx.clearRect(0, 0, canvas.width, canvas.height); 279 | 280 | // Draw shadow 281 | ctx.beginPath(); 282 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 283 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false); 284 | ctx.fillStyle = shadow; 285 | ctx.fill(); 286 | 287 | // Draw background 288 | ctx.beginPath(); 289 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 290 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 291 | ctx.fillStyle = background; 292 | ctx.fill(); 293 | 294 | // Draw pie 295 | if (percentage > 0) { 296 | ctx.beginPath(); 297 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 298 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 299 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 300 | ctx.fillStyle = color; 301 | ctx.fill(); 302 | } 303 | } 304 | 305 | setFaviconTag(canvas.toDataURL()); 306 | } 307 | }, { 308 | key: 'render', 309 | value: function render() { 310 | return null; 311 | } 312 | }]); 313 | return Pie; 314 | }(React.Component); 315 | 316 | Pie.propTypes = { 317 | percentage: PropTypes.number, 318 | color: PropTypes.string, 319 | background: PropTypes.string, 320 | shadow: PropTypes.string 321 | }; 322 | 323 | var Donut = function (_React$Component) { 324 | inherits(Donut, _React$Component); 325 | 326 | function Donut() { 327 | classCallCheck(this, Donut); 328 | return possibleConstructorReturn(this, (Donut.__proto__ || Object.getPrototypeOf(Donut)).apply(this, arguments)); 329 | } 330 | 331 | createClass(Donut, [{ 332 | key: 'componentDidMount', 333 | value: function componentDidMount() { 334 | this.drawFavicon(); 335 | } 336 | }, { 337 | key: 'componentDidUpdate', 338 | value: function componentDidUpdate(prevProps) { 339 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 340 | if (isPropsChanged) { 341 | this.drawFavicon(); 342 | } 343 | } 344 | }, { 345 | key: 'drawFavicon', 346 | value: function drawFavicon() { 347 | var _props = this.props, 348 | donutWidth = _props.donutWidth, 349 | percentage = _props.percentage, 350 | color = _props.color, 351 | background = _props.background, 352 | shadow = _props.shadow; 353 | 354 | var canvas = getCanvas(); 355 | var ctx = canvas.getContext('2d'); 356 | 357 | if (ctx) { 358 | ctx.clearRect(0, 0, canvas.width, canvas.height); 359 | 360 | // Draw shadow 361 | ctx.beginPath(); 362 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 363 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false); 364 | ctx.fillStyle = shadow; 365 | ctx.fill(); 366 | 367 | // Draw background 368 | ctx.beginPath(); 369 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 370 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 371 | ctx.fillStyle = background; 372 | ctx.fill(); 373 | 374 | // Draw donut 375 | if (percentage > 0) { 376 | ctx.beginPath(); 377 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 378 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 379 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 380 | ctx.fillStyle = color; 381 | ctx.fill(); 382 | 383 | ctx.beginPath(); 384 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 385 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - donutWidth, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 386 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 387 | ctx.fillStyle = background; 388 | ctx.fill(); 389 | } 390 | } 391 | 392 | setFaviconTag(canvas.toDataURL()); 393 | } 394 | }, { 395 | key: 'render', 396 | value: function render() { 397 | return null; 398 | } 399 | }]); 400 | return Donut; 401 | }(React.Component); 402 | 403 | Donut.propTypes = { 404 | donutWidth: PropTypes.number, 405 | percentage: PropTypes.number, 406 | color: PropTypes.string, 407 | background: PropTypes.string, 408 | shadow: PropTypes.string 409 | }; 410 | 411 | var Exception = function (_React$Component) { 412 | inherits(Exception, _React$Component); 413 | 414 | function Exception() { 415 | classCallCheck(this, Exception); 416 | return possibleConstructorReturn(this, (Exception.__proto__ || Object.getPrototypeOf(Exception)).apply(this, arguments)); 417 | } 418 | 419 | createClass(Exception, [{ 420 | key: 'componentDidMount', 421 | value: function componentDidMount() { 422 | this.drawFavicon(); 423 | } 424 | }, { 425 | key: 'drawFavicon', 426 | value: function drawFavicon() { 427 | var color = this.props.color; 428 | 429 | var canvas = getCanvas(); 430 | var ctx = canvas.getContext('2d'); 431 | 432 | ctx.clearRect(0, 0, canvas.width, canvas.height); 433 | 434 | // Draw background 435 | ctx.beginPath(); 436 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 437 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 438 | ctx.fillStyle = color; 439 | ctx.fill(); 440 | 441 | // Draw cross 442 | ctx.beginPath(); 443 | ctx.moveTo(canvas.width / 3, canvas.height / 3); 444 | ctx.lineTo(2 * canvas.width / 3, 2 * canvas.height / 3); 445 | ctx.lineWidth = 3; 446 | ctx.strokeStyle = '#fff'; 447 | ctx.stroke(); 448 | 449 | ctx.beginPath(); 450 | ctx.moveTo(canvas.width / 3, 2 * canvas.height / 3); 451 | ctx.lineTo(2 * canvas.width / 3, canvas.height / 3); 452 | ctx.lineWidth = 3; 453 | ctx.strokeStyle = '#fff'; 454 | ctx.stroke(); 455 | 456 | setFaviconTag(canvas.toDataURL()); 457 | } 458 | }, { 459 | key: 'render', 460 | value: function render() { 461 | return null; 462 | } 463 | }]); 464 | return Exception; 465 | }(React.Component); 466 | 467 | Exception.propTypes = { 468 | color: PropTypes.string 469 | }; 470 | 471 | Exception.defaultProps = { 472 | color: '#ff564e' 473 | }; 474 | 475 | var Success = function (_React$Component) { 476 | inherits(Success, _React$Component); 477 | 478 | function Success() { 479 | classCallCheck(this, Success); 480 | return possibleConstructorReturn(this, (Success.__proto__ || Object.getPrototypeOf(Success)).apply(this, arguments)); 481 | } 482 | 483 | createClass(Success, [{ 484 | key: 'componentDidMount', 485 | value: function componentDidMount() { 486 | this.drawFavicon(); 487 | } 488 | }, { 489 | key: 'drawFavicon', 490 | value: function drawFavicon() { 491 | var color = this.props.color; 492 | 493 | var canvas = getCanvas(); 494 | var ctx = canvas.getContext('2d'); 495 | 496 | if (ctx) { 497 | ctx.clearRect(0, 0, canvas.width, canvas.height); 498 | 499 | // Draw background 500 | ctx.beginPath(); 501 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 502 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 503 | ctx.fillStyle = color; 504 | ctx.fill(); 505 | 506 | // Draw tick 507 | ctx.beginPath(); 508 | ctx.moveTo(canvas.width * 0.22, canvas.height * 0.5); 509 | ctx.lineTo(canvas.width * 0.45, canvas.height * 0.7); 510 | ctx.lineTo(canvas.width * 0.73, canvas.height * 0.3); 511 | ctx.lineWidth = 3; 512 | ctx.strokeStyle = '#fff'; 513 | ctx.stroke(); 514 | } 515 | 516 | setFaviconTag(canvas.toDataURL()); 517 | } 518 | }, { 519 | key: 'render', 520 | value: function render() { 521 | return null; 522 | } 523 | }]); 524 | return Success; 525 | }(React.Component); 526 | 527 | Success.propTypes = { 528 | color: PropTypes.string 529 | }; 530 | 531 | Success.defaultProps = { 532 | color: '#25c639' 533 | }; 534 | 535 | var LoadCon = function (_React$Component) { 536 | inherits(LoadCon, _React$Component); 537 | 538 | function LoadCon() { 539 | var _ref; 540 | 541 | var _temp, _this, _ret; 542 | 543 | classCallCheck(this, LoadCon); 544 | 545 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 546 | args[_key] = arguments[_key]; 547 | } 548 | 549 | return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = LoadCon.__proto__ || Object.getPrototypeOf(LoadCon)).call.apply(_ref, [this].concat(args))), _this), _this.state = { 550 | originalFaviconURL: null 551 | }, _this._renderFavicon = function () { 552 | switch (_this.props.type) { 553 | default: 554 | case 'pie': 555 | return React.createElement(Pie, _this.props); 556 | case 'donut': 557 | return React.createElement(Donut, _this.props); 558 | } 559 | }, _this._resetFavicon = function () { 560 | var originalFaviconURL = _this.state.originalFaviconURL; 561 | 562 | setFaviconTag(originalFaviconURL); 563 | }, _temp), possibleConstructorReturn(_this, _ret); 564 | } 565 | 566 | createClass(LoadCon, [{ 567 | key: 'componentDidMount', 568 | value: function componentDidMount() { 569 | this.setState({ 570 | originalFaviconURL: getFaviconURL() 571 | }); 572 | } 573 | }, { 574 | key: 'componentDidUpdate', 575 | value: function componentDidUpdate(prevProps) { 576 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 577 | if (isPropsChanged) { 578 | if (this.props.status === 'normal') { 579 | this._resetFavicon(); 580 | } 581 | } 582 | } 583 | }, { 584 | key: 'render', 585 | value: function render() { 586 | var status = this.props.status; 587 | 588 | return React.createElement( 589 | NoSSR, 590 | null, 591 | status === 'active' && this._renderFavicon(), 592 | status === 'exception' && React.createElement(Exception, null), 593 | status === 'success' && React.createElement(Success, null) 594 | ); 595 | } 596 | }]); 597 | return LoadCon; 598 | }(React.Component); 599 | 600 | LoadCon.propTypes = { 601 | percentage: PropTypes.number.isRequired, 602 | type: PropTypes.oneOf(['pie', 'donut']), 603 | status: PropTypes.oneOf(['normal', 'active', 'exception', 'success']), 604 | color: PropTypes.string, 605 | background: PropTypes.string, 606 | shadow: PropTypes.string, 607 | donutWidth: PropTypes.number 608 | }; 609 | 610 | LoadCon.defaultProps = { 611 | percentage: 0, 612 | type: 'pie', 613 | status: 'normal', 614 | color: '#25c639', 615 | background: '#eee', 616 | shadow: '#fff', 617 | donutWidth: 8 618 | }; 619 | 620 | export default LoadCon; 621 | //# sourceMappingURL=index.es.js.map 622 | -------------------------------------------------------------------------------- /dist/index.es.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.es.js","sources":["../node_modules/react-fast-compare/index.js","../src/utils/NoSSR.js","../src/utils/index.js","../src/Favicons/Pie.js","../src/Favicons/Donut.js","../src/Favicons/Exception.js","../src/Favicons/Success.js","../src/index.js"],"sourcesContent":["'use strict';\n\nvar isArray = Array.isArray;\nvar keyList = Object.keys;\nvar hasProp = Object.prototype.hasOwnProperty;\nvar hasElementType = typeof Element !== 'undefined';\n\nfunction equal(a, b) {\n // fast-deep-equal index.js 2.0.1\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n var arrA = isArray(a)\n , arrB = isArray(b)\n , i\n , length\n , key;\n\n if (arrA && arrB) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n if (arrA != arrB) return false;\n\n var dateA = a instanceof Date\n , dateB = b instanceof Date;\n if (dateA != dateB) return false;\n if (dateA && dateB) return a.getTime() == b.getTime();\n\n var regexpA = a instanceof RegExp\n , regexpB = b instanceof RegExp;\n if (regexpA != regexpB) return false;\n if (regexpA && regexpB) return a.toString() == b.toString();\n\n var keys = keyList(a);\n length = keys.length;\n\n if (length !== keyList(b).length)\n return false;\n\n for (i = length; i-- !== 0;)\n if (!hasProp.call(b, keys[i])) return false;\n // end fast-deep-equal\n\n // start react-fast-compare\n // custom handling for DOM elements\n if (hasElementType && a instanceof Element && b instanceof Element)\n return a === b;\n\n // custom handling for React\n for (i = length; i-- !== 0;) {\n key = keys[i];\n if (key === '_owner' && a.$$typeof) {\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // .$$typeof and ._store on just reasonable markers of a react element\n continue;\n } else {\n // all other properties should be traversed as usual\n if (!equal(a[key], b[key])) return false;\n }\n }\n // end react-fast-compare\n\n // fast-deep-equal index.js 2.0.1\n return true;\n }\n\n return a !== a && b !== b;\n}\n// end fast-deep-equal\n\nmodule.exports = function exportedEqual(a, b) {\n try {\n return equal(a, b);\n } catch (error) {\n if ((error.message && error.message.match(/stack|recursion/i)) || (error.number === -2146828260)) {\n // warn on circular references, don't crash\n // browsers give this different errors name and messages:\n // chrome/safari: \"RangeError\", \"Maximum call stack size exceeded\"\n // firefox: \"InternalError\", too much recursion\"\n // edge: \"Error\", \"Out of stack space\"\n console.warn('Warning: react-fast-compare does not handle circular references.', error.name, error.message);\n return false;\n }\n // some other error. we should definitely know about these\n throw error;\n }\n};\n","import React, { Component } from 'react'\n\nconst DefaultOnSSR = () => ()\n\nclass NoSSR extends Component {\n state = {\n canRender: false\n }\n\n componentDidMount() {\n this.setState({ canRender: true })\n }\n\n render() {\n const { children, onSSR = } = this.props\n\n return (\n \n {this.state.canRender ? children : onSSR}\n \n )\n }\n}\n\nexport default NoSSR\n","const isUA = (browser) => {\n const agent = navigator.userAgent.toLowerCase()\n return agent.indexOf(browser) !== 1\n}\n\nexport const getIsRetina = () => {\n return window.devicePixelRatio > 1\n}\n\nexport const getBrowser = () => {\n if (isUA('msie')) {\n return 'ie'\n } else if (isUA('chrome')) {\n return 'chrome'\n } else if (isUA('chrome') || isUA('safari')) {\n return 'webkit'\n } else if (isUA('safari') && !isUA('chrome')) {\n return 'safari'\n } else if (isUA('mozilla') && !isUA('chrome') && !isUA('safari')) {\n return 'mozilla'\n }\n}\n\nexport const getFaviconURL = () => {\n const links = document.getElementsByTagName('link')\n let tag = null\n\n for (let i = 0, l = links.length; i < l; i++) {\n if (links[i].getAttribute('rel') === 'icon'\n || links[i].getAttribute('rel') === 'shortcut icon') {\n tag = links[i]\n }\n }\n\n return tag ? tag.getAttribute('href') : '/favicon.ico'\n}\n\nexport const removeFaviconTag = () => {\n const links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0)\n const head = document.getElementsByTagName('head')[0]\n\n for (let i = 0, l = links.length; i < l; i++) {\n if (links[i].getAttribute('rel') === 'icon'\n || links[i].getAttribute('rel') === 'shortcut icon') {\n head.removeChild(links[i])\n }\n }\n}\n\nexport const setFaviconTag = (url) => {\n removeFaviconTag()\n\n const link = document.createElement('link')\n link.type = 'image/x-icon'\n link.rel = 'icon'\n link.href = url\n\n document.getElementsByTagName('head')[0].appendChild(link)\n}\n\nexport const getCanvas = function () {\n const canvas = document.createElement(\"canvas\")\n if (getIsRetina()) {\n canvas.width = 32\n canvas.height = 32\n } else {\n canvas.width = 16\n canvas.height = 16\n }\n\n return canvas\n}\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Pie extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n this.drawFavicon()\n }\n }\n\n drawFavicon () {\n const { percentage, color, background, shadow } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw shadow\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false)\n ctx.fillStyle = shadow\n ctx.fill()\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = background\n ctx.fill()\n\n // Draw pie\n if (percentage > 0) {\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = color\n ctx.fill()\n }\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nPie.propTypes = {\n percentage: PropTypes.number,\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n}\n\nexport default Pie\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Donut extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n this.drawFavicon()\n }\n }\n\n drawFavicon () {\n const { donutWidth, percentage, color, background, shadow } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw shadow\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false)\n ctx.fillStyle = shadow\n ctx.fill()\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = background\n ctx.fill()\n\n // Draw donut\n if (percentage > 0) {\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = color\n ctx.fill()\n\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - donutWidth, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = background\n ctx.fill()\n }\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nDonut.propTypes = {\n donutWidth: PropTypes.number,\n percentage: PropTypes.number,\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n}\n\nexport default Donut\n","import React from 'react'\nimport PropTypes from 'prop-types'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Exception extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n drawFavicon () {\n const { color } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = color\n ctx.fill()\n\n // Draw cross\n ctx.beginPath()\n ctx.moveTo(canvas.width / 3, canvas.height / 3)\n ctx.lineTo(2 * canvas.width / 3, 2 * canvas.height / 3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n\n ctx.beginPath()\n ctx.moveTo(canvas.width / 3, 2 * canvas.height / 3)\n ctx.lineTo(2 * canvas.width / 3, canvas.height / 3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nException.propTypes = {\n color: PropTypes.string,\n}\n\nException.defaultProps = {\n color: '#ff564e'\n}\n\nexport default Exception\n","import React from 'react'\nimport PropTypes from 'prop-types'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Success extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n drawFavicon () {\n const { color } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = color\n ctx.fill()\n\n // Draw tick\n ctx.beginPath()\n ctx.moveTo(canvas.width * 0.22, canvas.height * 0.5)\n ctx.lineTo(canvas.width * 0.45, canvas.height * 0.7)\n ctx.lineTo(canvas.width * 0.73, canvas.height * 0.3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nSuccess.propTypes = {\n color: PropTypes.string,\n}\n\nSuccess.defaultProps = {\n color: '#25c639'\n}\n\nexport default Success\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport NoSSR from './utils/NoSSR'\nimport { getFaviconURL, setFaviconTag } from './utils'\n\nimport PieCon from './Favicons/Pie'\nimport DonutCon from './Favicons/Donut'\nimport ExceptionCon from './Favicons/Exception'\nimport SuccessCon from './Favicons/Success'\n\nclass LoadCon extends React.Component {\n state = {\n originalFaviconURL: null\n }\n\n componentDidMount () {\n this.setState({\n originalFaviconURL: getFaviconURL()\n })\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n if (this.props.status === 'normal') {\n this._resetFavicon()\n }\n }\n }\n\n _renderFavicon = () => {\n switch (this.props.type) {\n default:\n case 'pie':\n return \n case 'donut':\n return \n }\n }\n\n _resetFavicon = () => {\n const { originalFaviconURL } = this.state\n setFaviconTag(originalFaviconURL)\n }\n\n render() {\n const { status } = this.props\n return (\n \n {status === 'active' && this._renderFavicon()}\n {status === 'exception' && }\n {status === 'success' && }\n \n )\n }\n}\n\nLoadCon.propTypes = {\n percentage: PropTypes.number.isRequired,\n type: PropTypes.oneOf(['pie', 'donut']),\n status: PropTypes.oneOf(['normal', 'active', 'exception', 'success']),\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n donutWidth: PropTypes.number,\n}\n\nLoadCon.defaultProps = {\n percentage: 0,\n type: 'pie',\n status: 'normal',\n color: '#25c639',\n background: '#eee',\n shadow: '#fff',\n donutWidth: 8,\n}\n\nexport default LoadCon\n"],"names":["DefaultOnSSR","NoSSR","state","setState","canRender","props","children","onSSR","Component","getIsRetina","window","devicePixelRatio","getFaviconURL","links","document","getElementsByTagName","tag","i","l","length","getAttribute","removeFaviconTag","Array","prototype","slice","call","head","removeChild","setFaviconTag","url","link","createElement","type","rel","href","appendChild","getCanvas","canvas","width","height","Pie","drawFavicon","prevProps","isPropsChanged","isEqual","percentage","color","background","shadow","ctx","getContext","clearRect","beginPath","moveTo","arc","Math","min","PI","fillStyle","fill","lineTo","toDataURL","React","propTypes","PropTypes","number","string","Donut","donutWidth","Exception","lineWidth","strokeStyle","stroke","defaultProps","Success","LoadCon","_renderFavicon","PieCon","DonutCon","_resetFavicon","originalFaviconURL","status","ExceptionCon","SuccessCon","isRequired","oneOf"],"mappings":";;;AAEA,IAAI,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;AAC5B,IAAI,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AAC1B,IAAI,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC;AAC9C,IAAI,cAAc,GAAG,OAAO,OAAO,KAAK,WAAW,CAAC;;AAEpD,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;;EAEnB,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,IAAI,CAAC;;EAEzB,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,QAAQ,IAAI,OAAO,CAAC,IAAI,QAAQ,EAAE;IAC1D,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC;QACjB,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,MAAM;QACN,GAAG,CAAC;;IAER,IAAI,IAAI,IAAI,IAAI,EAAE;MAChB,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;MAClB,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,CAAC;MACrC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC;MACvC,OAAO,IAAI,CAAC;KACb;;IAED,IAAI,IAAI,IAAI,IAAI,EAAE,OAAO,KAAK,CAAC;;IAE/B,IAAI,KAAK,GAAG,CAAC,YAAY,IAAI;QACzB,KAAK,GAAG,CAAC,YAAY,IAAI,CAAC;IAC9B,IAAI,KAAK,IAAI,KAAK,EAAE,OAAO,KAAK,CAAC;IACjC,IAAI,KAAK,IAAI,KAAK,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;;IAEtD,IAAI,OAAO,GAAG,CAAC,YAAY,MAAM;QAC7B,OAAO,GAAG,CAAC,YAAY,MAAM,CAAC;IAClC,IAAI,OAAO,IAAI,OAAO,EAAE,OAAO,KAAK,CAAC;IACrC,IAAI,OAAO,IAAI,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;;IAE5D,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;;IAErB,IAAI,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM;MAC9B,OAAO,KAAK,CAAC;;IAEf,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC;MACxB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC;;;;;IAK9C,IAAI,cAAc,IAAI,CAAC,YAAY,OAAO,IAAI,CAAC,YAAY,OAAO;MAChE,OAAO,CAAC,KAAK,CAAC,CAAC;;;IAGjB,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG;MAC3B,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;MACd,IAAI,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,EAAE;;;;;QAKlC,SAAS;OACV,MAAM;;QAEL,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC;OAC1C;KACF;;;;IAID,OAAO,IAAI,CAAC;GACb;;EAED,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;CAC3B;;;AAGD,oBAAc,GAAG,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE;EAC5C,IAAI;IACF,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;GACpB,CAAC,OAAO,KAAK,EAAE;IACd,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,EAAE;;;;;;MAMhG,OAAO,CAAC,IAAI,CAAC,kEAAkE,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;MAC5G,OAAO,KAAK,CAAC;KACd;;IAED,MAAM,KAAK,CAAC;GACb;CACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3FF,IAAMA,eAAe,SAAfA,YAAe;SAAO,iCAAP;CAArB;;IAEMC;;;;;;;;;;;;;;mLACJC,QAAQ;iBACK;;;;;;wCAGO;WACbC,QAAL,CAAc,EAAEC,WAAW,IAAb,EAAd;;;;6BAGO;mBACuC,KAAKC,KAD5C;UACCC,QADD,UACCA,QADD;gCACWC,KADX;UACWA,KADX,gCACmB,oBAAC,YAAD,OADnB;;;aAIL;aAAA,CAAO,QAAP;;aACQL,KAAL,CAAWE,SAAX,GAAuBE,QAAvB,GAAkCC;OAFvC;;;;EAZgBC;;ACCb,IAAMC,cAAc,SAAdA,WAAc,GAAM;SACxBC,OAAOC,gBAAP,GAA0B,CAAjC;CADK;;AAkBP,AAAO,IAAMC,gBAAgB,SAAhBA,aAAgB,GAAM;MAC3BC,QAAQC,SAASC,oBAAT,CAA8B,MAA9B,CAAd;MACIC,MAAM,IAAV;;OAEK,IAAIC,IAAI,CAAR,EAAWC,IAAIL,MAAMM,MAA1B,EAAkCF,IAAIC,CAAtC,EAAyCD,GAAzC,EAA8C;QACxCJ,MAAMI,CAAN,EAASG,YAAT,CAAsB,KAAtB,MAAiC,MAAjC,IACCP,MAAMI,CAAN,EAASG,YAAT,CAAsB,KAAtB,MAAiC,eADtC,EACuD;YAC/CP,MAAMI,CAAN,CAAN;;;;SAIGD,MAAMA,IAAII,YAAJ,CAAiB,MAAjB,CAAN,GAAiC,cAAxC;CAXK;;AAcP,AAAO,IAAMC,mBAAmB,SAAnBA,gBAAmB,GAAM;MAC9BR,QAAQS,MAAMC,SAAN,CAAgBC,KAAhB,CAAsBC,IAAtB,CAA2BX,SAASC,oBAAT,CAA8B,MAA9B,CAA3B,EAAkE,CAAlE,CAAd;MACMW,OAAOZ,SAASC,oBAAT,CAA8B,MAA9B,EAAsC,CAAtC,CAAb;;OAEK,IAAIE,IAAI,CAAR,EAAWC,IAAIL,MAAMM,MAA1B,EAAkCF,IAAIC,CAAtC,EAAyCD,GAAzC,EAA8C;QACxCJ,MAAMI,CAAN,EAASG,YAAT,CAAsB,KAAtB,MAAiC,MAAjC,IACCP,MAAMI,CAAN,EAASG,YAAT,CAAsB,KAAtB,MAAiC,eADtC,EACuD;WAChDO,WAAL,CAAiBd,MAAMI,CAAN,CAAjB;;;CAPC;;AAYP,AAAO,IAAMW,gBAAgB,SAAhBA,aAAgB,CAACC,GAAD,EAAS;;;MAG9BC,OAAOhB,SAASiB,aAAT,CAAuB,MAAvB,CAAb;OACKC,IAAL,GAAY,cAAZ;OACKC,GAAL,GAAW,MAAX;OACKC,IAAL,GAAYL,GAAZ;;WAESd,oBAAT,CAA8B,MAA9B,EAAsC,CAAtC,EAAyCoB,WAAzC,CAAqDL,IAArD;CARK;;AAWP,AAAO,IAAMM,YAAY,SAAZA,SAAY,GAAY;MAC7BC,SAASvB,SAASiB,aAAT,CAAuB,QAAvB,CAAf;MACItB,aAAJ,EAAmB;WACV6B,KAAP,GAAe,EAAf;WACOC,MAAP,GAAgB,EAAhB;GAFF,MAGO;WACED,KAAP,GAAe,EAAf;WACOC,MAAP,GAAgB,EAAhB;;;SAGKF,MAAP;CAVK;;ICtDDG;;;;;;;;;;wCACiB;WACdC,WAAL;;;;uCAGkBC,WAAW;UACvBC,iBAAiB,CAACC,iBAAQ,KAAKvC,KAAb,EAAoBqC,SAApB,CAAxB;UACIC,cAAJ,EAAoB;aACbF,WAAL;;;;;kCAIW;mBACqC,KAAKpC,KAD1C;UACLwC,UADK,UACLA,UADK;UACOC,KADP,UACOA,KADP;UACcC,UADd,UACcA,UADd;UAC0BC,MAD1B,UAC0BA,MAD1B;;UAEPX,SAASD,WAAf;UACMa,MAAMZ,OAAOa,UAAP,CAAkB,IAAlB,CAAZ;;UAEID,GAAJ,EAAS;YACHE,SAAJ,CAAc,CAAd,EAAiB,CAAjB,EAAoBd,OAAOC,KAA3B,EAAkCD,OAAOE,MAAzC;;;YAGIa,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;YACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,CAA7C,EAA4F,CAA5F,EAA+FgB,KAAKE,EAAL,GAAU,CAAzG,EAA4G,KAA5G;YACIC,SAAJ,GAAgBV,MAAhB;YACIW,IAAJ;;;YAGIP,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;YACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAgG,CAAhG,EAAmGgB,KAAKE,EAAL,GAAU,CAA7G,EAAgH,KAAhH;YACIC,SAAJ,GAAgBX,UAAhB;YACIY,IAAJ;;;YAGId,aAAa,CAAjB,EAAoB;cACdO,SAAJ;cACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAiG,CAAC,GAAF,GAASgB,KAAKE,EAA9G,EAAkH,CAAC,CAAC,GAAD,GAAO,IAAIZ,UAAJ,GAAiB,GAAzB,IAAgCU,KAAKE,EAAvJ,EAA2J,KAA3J;cACIG,MAAJ,CAAWvB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACImB,SAAJ,GAAgBZ,KAAhB;cACIa,IAAJ;;;;oBAIUtB,OAAOwB,SAAP,EAAd;;;;6BAGQ;aACA,IAAR;;;;EAjDcC,MAAMtD;;AAqDxBgC,IAAIuB,SAAJ,GAAgB;cACFC,UAAUC,MADR;SAEPD,UAAUE,MAFH;cAGFF,UAAUE,MAHR;UAINF,UAAUE;CAJpB;;ICrDMC;;;;;;;;;;wCACiB;WACd1B,WAAL;;;;uCAGkBC,WAAW;UACvBC,iBAAiB,CAACC,iBAAQ,KAAKvC,KAAb,EAAoBqC,SAApB,CAAxB;UACIC,cAAJ,EAAoB;aACbF,WAAL;;;;;kCAIW;mBACiD,KAAKpC,KADtD;UACL+D,UADK,UACLA,UADK;UACOvB,UADP,UACOA,UADP;UACmBC,KADnB,UACmBA,KADnB;UAC0BC,UAD1B,UAC0BA,UAD1B;UACsCC,MADtC,UACsCA,MADtC;;UAEPX,SAASD,WAAf;UACMa,MAAMZ,OAAOa,UAAP,CAAkB,IAAlB,CAAZ;;UAEID,GAAJ,EAAS;YACHE,SAAJ,CAAc,CAAd,EAAiB,CAAjB,EAAoBd,OAAOC,KAA3B,EAAkCD,OAAOE,MAAzC;;;YAGIa,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;YACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,CAA7C,EAA4F,CAA5F,EAA+FgB,KAAKE,EAAL,GAAU,CAAzG,EAA4G,KAA5G;YACIC,SAAJ,GAAgBV,MAAhB;YACIW,IAAJ;;;YAGIP,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;YACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAgG,CAAhG,EAAmGgB,KAAKE,EAAL,GAAU,CAA7G,EAAgH,KAAhH;YACIC,SAAJ,GAAgBX,UAAhB;YACIY,IAAJ;;;YAGId,aAAa,CAAjB,EAAoB;cACdO,SAAJ;cACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAiG,CAAC,GAAF,GAASgB,KAAKE,EAA9G,EAAkH,CAAC,CAAC,GAAD,GAAO,IAAIZ,UAAJ,GAAiB,GAAzB,IAAgCU,KAAKE,EAAvJ,EAA2J,KAA3J;cACIG,MAAJ,CAAWvB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACImB,SAAJ,GAAgBZ,KAAhB;cACIa,IAAJ;;cAEIP,SAAJ;cACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD6B,UAA7F,EAA0G,CAAC,GAAF,GAASb,KAAKE,EAAvH,EAA2H,CAAC,CAAC,GAAD,GAAO,IAAIZ,UAAJ,GAAiB,GAAzB,IAAgCU,KAAKE,EAAhK,EAAoK,KAApK;cACIG,MAAJ,CAAWvB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;cACImB,SAAJ,GAAgBX,UAAhB;cACIY,IAAJ;;;;oBAIUtB,OAAOwB,SAAP,EAAd;;;;6BAGQ;aACA,IAAR;;;;EAxDgBC,MAAMtD;;AA4D1B2D,MAAMJ,SAAN,GAAkB;cACJC,UAAUC,MADN;cAEJD,UAAUC,MAFN;SAGTD,UAAUE,MAHD;cAIJF,UAAUE,MAJN;UAKRF,UAAUE;CALpB;;IC7DMG;;;;;;;;;;wCACiB;WACd5B,WAAL;;;;kCAGa;UACLK,KADK,GACK,KAAKzC,KADV,CACLyC,KADK;;UAEPT,SAASD,WAAf;UACMa,MAAMZ,OAAOa,UAAP,CAAkB,IAAlB,CAAZ;;UAEIC,SAAJ,CAAc,CAAd,EAAiB,CAAjB,EAAoBd,OAAOC,KAA3B,EAAkCD,OAAOE,MAAzC;;;UAGIa,SAAJ;UACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;UACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAgG,CAAhG,EAAmGgB,KAAKE,EAAL,GAAU,CAA7G,EAAgH,KAAhH;UACIC,SAAJ,GAAgBZ,KAAhB;UACIa,IAAJ;;;UAGIP,SAAJ;UACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;UACIqB,MAAJ,CAAW,IAAIvB,OAAOC,KAAX,GAAmB,CAA9B,EAAiC,IAAID,OAAOE,MAAX,GAAoB,CAArD;UACI+B,SAAJ,GAAgB,CAAhB;UACIC,WAAJ,GAAkB,MAAlB;UACIC,MAAJ;;UAEIpB,SAAJ;UACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6B,IAAID,OAAOE,MAAX,GAAoB,CAAjD;UACIqB,MAAJ,CAAW,IAAIvB,OAAOC,KAAX,GAAmB,CAA9B,EAAiCD,OAAOE,MAAP,GAAgB,CAAjD;UACI+B,SAAJ,GAAgB,CAAhB;UACIC,WAAJ,GAAkB,MAAlB;UACIC,MAAJ;;oBAEcnC,OAAOwB,SAAP,EAAd;;;;6BAGQ;aACA,IAAR;;;;EAtCoBC,MAAMtD;;AA0C9B6D,UAAUN,SAAV,GAAsB;SACbC,UAAUE;CADnB;;AAIAG,UAAUI,YAAV,GAAyB;SAChB;CADT;;IC9CMC;;;;;;;;;;wCACiB;WACdjC,WAAL;;;;kCAGa;UACLK,KADK,GACK,KAAKzC,KADV,CACLyC,KADK;;UAEPT,SAASD,WAAf;UACMa,MAAMZ,OAAOa,UAAP,CAAkB,IAAlB,CAAZ;;UAEID,GAAJ,EAAS;YACHE,SAAJ,CAAc,CAAd,EAAiB,CAAjB,EAAoBd,OAAOC,KAA3B,EAAkCD,OAAOE,MAAzC;;;YAGIa,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,CAA1B,EAA6BD,OAAOE,MAAP,GAAgB,CAA7C;YACIe,GAAJ,CAAQjB,OAAOC,KAAP,GAAe,CAAvB,EAA0BD,OAAOE,MAAP,GAAgB,CAA1C,EAA6CgB,KAAKC,GAAL,CAASnB,OAAOC,KAAP,GAAe,CAAxB,EAA2BD,OAAOE,MAAP,GAAgB,CAA3C,IAAgD,CAA7F,EAAgG,CAAhG,EAAmGgB,KAAKE,EAAL,GAAU,CAA7G,EAAgH,KAAhH;YACIC,SAAJ,GAAgBZ,KAAhB;YACIa,IAAJ;;;YAGIP,SAAJ;YACIC,MAAJ,CAAWhB,OAAOC,KAAP,GAAe,IAA1B,EAAgCD,OAAOE,MAAP,GAAgB,GAAhD;YACIqB,MAAJ,CAAWvB,OAAOC,KAAP,GAAe,IAA1B,EAAgCD,OAAOE,MAAP,GAAgB,GAAhD;YACIqB,MAAJ,CAAWvB,OAAOC,KAAP,GAAe,IAA1B,EAAgCD,OAAOE,MAAP,GAAgB,GAAhD;YACI+B,SAAJ,GAAgB,CAAhB;YACIC,WAAJ,GAAkB,MAAlB;YACIC,MAAJ;;;oBAGYnC,OAAOwB,SAAP,EAAd;;;;6BAGQ;aACA,IAAR;;;;EAlCkBC,MAAMtD;;AAsC5BkE,QAAQX,SAAR,GAAoB;SACXC,UAAUE;CADnB;;AAIAQ,QAAQD,YAAR,GAAuB;SACd;CADT;;ICnCME;;;;;;;;;;;;;;uLACJzE,QAAQ;0BACc;aAkBtB0E,iBAAiB,YAAM;cACb,MAAKvE,KAAL,CAAW2B,IAAnB;;aAEO,KAAL;iBACS,oBAAC6C,GAAD,EAAY,MAAKxE,KAAjB,CAAP;aACG,OAAL;iBACS,oBAACyE,KAAD,EAAc,MAAKzE,KAAnB,CAAP;;aAIN0E,gBAAgB,YAAM;UACZC,kBADY,GACW,MAAK9E,KADhB,CACZ8E,kBADY;;oBAENA,kBAAd;;;;;;wCA3BmB;WACd7E,QAAL,CAAc;4BACQS;OADtB;;;;uCAKkB8B,WAAW;UACvBC,iBAAiB,CAACC,iBAAQ,KAAKvC,KAAb,EAAoBqC,SAApB,CAAxB;UACIC,cAAJ,EAAoB;YACd,KAAKtC,KAAL,CAAW4E,MAAX,KAAsB,QAA1B,EAAoC;eAC7BF,aAAL;;;;;;6BAoBG;UACCE,MADD,GACY,KAAK5E,KADjB,CACC4E,MADD;;aAGL;aAAA;;mBACc,QAAX,IAAuB,KAAKL,cAAL,EAD1B;mBAEc,WAAX,IAA0B,oBAACM,SAAD,OAF7B;mBAGc,SAAX,IAAwB,oBAACC,OAAD;OAJ7B;;;;EArCkBrB,MAAMtD;;AA+C5BmE,QAAQZ,SAAR,GAAoB;cACNC,UAAUC,MAAV,CAAiBmB,UADX;QAEZpB,UAAUqB,KAAV,CAAgB,CAAC,KAAD,EAAQ,OAAR,CAAhB,CAFY;UAGVrB,UAAUqB,KAAV,CAAgB,CAAC,QAAD,EAAW,QAAX,EAAqB,WAArB,EAAkC,SAAlC,CAAhB,CAHU;SAIXrB,UAAUE,MAJC;cAKNF,UAAUE,MALJ;UAMVF,UAAUE,MANA;cAONF,UAAUC;CAPxB;;AAUAU,QAAQF,YAAR,GAAuB;cACT,CADS;QAEf,KAFe;UAGb,QAHa;SAId,SAJc;cAKT,MALS;UAMb,MANa;cAOT;CAPd;;;;"} -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 4 | 5 | var React = require('react'); 6 | var React__default = _interopDefault(React); 7 | var PropTypes = _interopDefault(require('prop-types')); 8 | 9 | var isArray = Array.isArray; 10 | var keyList = Object.keys; 11 | var hasProp = Object.prototype.hasOwnProperty; 12 | var hasElementType = typeof Element !== 'undefined'; 13 | 14 | function equal(a, b) { 15 | // fast-deep-equal index.js 2.0.1 16 | if (a === b) return true; 17 | 18 | if (a && b && typeof a == 'object' && typeof b == 'object') { 19 | var arrA = isArray(a) 20 | , arrB = isArray(b) 21 | , i 22 | , length 23 | , key; 24 | 25 | if (arrA && arrB) { 26 | length = a.length; 27 | if (length != b.length) return false; 28 | for (i = length; i-- !== 0;) 29 | if (!equal(a[i], b[i])) return false; 30 | return true; 31 | } 32 | 33 | if (arrA != arrB) return false; 34 | 35 | var dateA = a instanceof Date 36 | , dateB = b instanceof Date; 37 | if (dateA != dateB) return false; 38 | if (dateA && dateB) return a.getTime() == b.getTime(); 39 | 40 | var regexpA = a instanceof RegExp 41 | , regexpB = b instanceof RegExp; 42 | if (regexpA != regexpB) return false; 43 | if (regexpA && regexpB) return a.toString() == b.toString(); 44 | 45 | var keys = keyList(a); 46 | length = keys.length; 47 | 48 | if (length !== keyList(b).length) 49 | return false; 50 | 51 | for (i = length; i-- !== 0;) 52 | if (!hasProp.call(b, keys[i])) return false; 53 | // end fast-deep-equal 54 | 55 | // start react-fast-compare 56 | // custom handling for DOM elements 57 | if (hasElementType && a instanceof Element && b instanceof Element) 58 | return a === b; 59 | 60 | // custom handling for React 61 | for (i = length; i-- !== 0;) { 62 | key = keys[i]; 63 | if (key === '_owner' && a.$$typeof) { 64 | // React-specific: avoid traversing React elements' _owner. 65 | // _owner contains circular references 66 | // and is not needed when comparing the actual elements (and not their owners) 67 | // .$$typeof and ._store on just reasonable markers of a react element 68 | continue; 69 | } else { 70 | // all other properties should be traversed as usual 71 | if (!equal(a[key], b[key])) return false; 72 | } 73 | } 74 | // end react-fast-compare 75 | 76 | // fast-deep-equal index.js 2.0.1 77 | return true; 78 | } 79 | 80 | return a !== a && b !== b; 81 | } 82 | // end fast-deep-equal 83 | 84 | var reactFastCompare = function exportedEqual(a, b) { 85 | try { 86 | return equal(a, b); 87 | } catch (error) { 88 | if ((error.message && error.message.match(/stack|recursion/i)) || (error.number === -2146828260)) { 89 | // warn on circular references, don't crash 90 | // browsers give this different errors name and messages: 91 | // chrome/safari: "RangeError", "Maximum call stack size exceeded" 92 | // firefox: "InternalError", too much recursion" 93 | // edge: "Error", "Out of stack space" 94 | console.warn('Warning: react-fast-compare does not handle circular references.', error.name, error.message); 95 | return false; 96 | } 97 | // some other error. we should definitely know about these 98 | throw error; 99 | } 100 | }; 101 | 102 | var classCallCheck = function (instance, Constructor) { 103 | if (!(instance instanceof Constructor)) { 104 | throw new TypeError("Cannot call a class as a function"); 105 | } 106 | }; 107 | 108 | var createClass = function () { 109 | function defineProperties(target, props) { 110 | for (var i = 0; i < props.length; i++) { 111 | var descriptor = props[i]; 112 | descriptor.enumerable = descriptor.enumerable || false; 113 | descriptor.configurable = true; 114 | if ("value" in descriptor) descriptor.writable = true; 115 | Object.defineProperty(target, descriptor.key, descriptor); 116 | } 117 | } 118 | 119 | return function (Constructor, protoProps, staticProps) { 120 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 121 | if (staticProps) defineProperties(Constructor, staticProps); 122 | return Constructor; 123 | }; 124 | }(); 125 | 126 | var inherits = function (subClass, superClass) { 127 | if (typeof superClass !== "function" && superClass !== null) { 128 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 129 | } 130 | 131 | subClass.prototype = Object.create(superClass && superClass.prototype, { 132 | constructor: { 133 | value: subClass, 134 | enumerable: false, 135 | writable: true, 136 | configurable: true 137 | } 138 | }); 139 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 140 | }; 141 | 142 | var possibleConstructorReturn = function (self, call) { 143 | if (!self) { 144 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 145 | } 146 | 147 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 148 | }; 149 | 150 | var DefaultOnSSR = function DefaultOnSSR() { 151 | return React__default.createElement('span', null); 152 | }; 153 | 154 | var NoSSR = function (_Component) { 155 | inherits(NoSSR, _Component); 156 | 157 | function NoSSR() { 158 | var _ref; 159 | 160 | var _temp, _this, _ret; 161 | 162 | classCallCheck(this, NoSSR); 163 | 164 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 165 | args[_key] = arguments[_key]; 166 | } 167 | 168 | return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = NoSSR.__proto__ || Object.getPrototypeOf(NoSSR)).call.apply(_ref, [this].concat(args))), _this), _this.state = { 169 | canRender: false 170 | }, _temp), possibleConstructorReturn(_this, _ret); 171 | } 172 | 173 | createClass(NoSSR, [{ 174 | key: 'componentDidMount', 175 | value: function componentDidMount() { 176 | this.setState({ canRender: true }); 177 | } 178 | }, { 179 | key: 'render', 180 | value: function render() { 181 | var _props = this.props, 182 | children = _props.children, 183 | _props$onSSR = _props.onSSR, 184 | onSSR = _props$onSSR === undefined ? React__default.createElement(DefaultOnSSR, null) : _props$onSSR; 185 | 186 | 187 | return React__default.createElement( 188 | React__default.Fragment, 189 | null, 190 | this.state.canRender ? children : onSSR 191 | ); 192 | } 193 | }]); 194 | return NoSSR; 195 | }(React.Component); 196 | 197 | var getIsRetina = function getIsRetina() { 198 | return window.devicePixelRatio > 1; 199 | }; 200 | 201 | var getFaviconURL = function getFaviconURL() { 202 | var links = document.getElementsByTagName('link'); 203 | var tag = null; 204 | 205 | for (var i = 0, l = links.length; i < l; i++) { 206 | if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') { 207 | tag = links[i]; 208 | } 209 | } 210 | 211 | return tag ? tag.getAttribute('href') : '/favicon.ico'; 212 | }; 213 | 214 | var removeFaviconTag = function removeFaviconTag() { 215 | var links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0); 216 | var head = document.getElementsByTagName('head')[0]; 217 | 218 | for (var i = 0, l = links.length; i < l; i++) { 219 | if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') { 220 | head.removeChild(links[i]); 221 | } 222 | } 223 | }; 224 | 225 | var setFaviconTag = function setFaviconTag(url) { 226 | removeFaviconTag(); 227 | 228 | var link = document.createElement('link'); 229 | link.type = 'image/x-icon'; 230 | link.rel = 'icon'; 231 | link.href = url; 232 | 233 | document.getElementsByTagName('head')[0].appendChild(link); 234 | }; 235 | 236 | var getCanvas = function getCanvas() { 237 | var canvas = document.createElement("canvas"); 238 | if (getIsRetina()) { 239 | canvas.width = 32; 240 | canvas.height = 32; 241 | } else { 242 | canvas.width = 16; 243 | canvas.height = 16; 244 | } 245 | 246 | return canvas; 247 | }; 248 | 249 | var Pie = function (_React$Component) { 250 | inherits(Pie, _React$Component); 251 | 252 | function Pie() { 253 | classCallCheck(this, Pie); 254 | return possibleConstructorReturn(this, (Pie.__proto__ || Object.getPrototypeOf(Pie)).apply(this, arguments)); 255 | } 256 | 257 | createClass(Pie, [{ 258 | key: 'componentDidMount', 259 | value: function componentDidMount() { 260 | this.drawFavicon(); 261 | } 262 | }, { 263 | key: 'componentDidUpdate', 264 | value: function componentDidUpdate(prevProps) { 265 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 266 | if (isPropsChanged) { 267 | this.drawFavicon(); 268 | } 269 | } 270 | }, { 271 | key: 'drawFavicon', 272 | value: function drawFavicon() { 273 | var _props = this.props, 274 | percentage = _props.percentage, 275 | color = _props.color, 276 | background = _props.background, 277 | shadow = _props.shadow; 278 | 279 | var canvas = getCanvas(); 280 | var ctx = canvas.getContext('2d'); 281 | 282 | if (ctx) { 283 | ctx.clearRect(0, 0, canvas.width, canvas.height); 284 | 285 | // Draw shadow 286 | ctx.beginPath(); 287 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 288 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false); 289 | ctx.fillStyle = shadow; 290 | ctx.fill(); 291 | 292 | // Draw background 293 | ctx.beginPath(); 294 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 295 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 296 | ctx.fillStyle = background; 297 | ctx.fill(); 298 | 299 | // Draw pie 300 | if (percentage > 0) { 301 | ctx.beginPath(); 302 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 303 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 304 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 305 | ctx.fillStyle = color; 306 | ctx.fill(); 307 | } 308 | } 309 | 310 | setFaviconTag(canvas.toDataURL()); 311 | } 312 | }, { 313 | key: 'render', 314 | value: function render() { 315 | return null; 316 | } 317 | }]); 318 | return Pie; 319 | }(React__default.Component); 320 | 321 | Pie.propTypes = { 322 | percentage: PropTypes.number, 323 | color: PropTypes.string, 324 | background: PropTypes.string, 325 | shadow: PropTypes.string 326 | }; 327 | 328 | var Donut = function (_React$Component) { 329 | inherits(Donut, _React$Component); 330 | 331 | function Donut() { 332 | classCallCheck(this, Donut); 333 | return possibleConstructorReturn(this, (Donut.__proto__ || Object.getPrototypeOf(Donut)).apply(this, arguments)); 334 | } 335 | 336 | createClass(Donut, [{ 337 | key: 'componentDidMount', 338 | value: function componentDidMount() { 339 | this.drawFavicon(); 340 | } 341 | }, { 342 | key: 'componentDidUpdate', 343 | value: function componentDidUpdate(prevProps) { 344 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 345 | if (isPropsChanged) { 346 | this.drawFavicon(); 347 | } 348 | } 349 | }, { 350 | key: 'drawFavicon', 351 | value: function drawFavicon() { 352 | var _props = this.props, 353 | donutWidth = _props.donutWidth, 354 | percentage = _props.percentage, 355 | color = _props.color, 356 | background = _props.background, 357 | shadow = _props.shadow; 358 | 359 | var canvas = getCanvas(); 360 | var ctx = canvas.getContext('2d'); 361 | 362 | if (ctx) { 363 | ctx.clearRect(0, 0, canvas.width, canvas.height); 364 | 365 | // Draw shadow 366 | ctx.beginPath(); 367 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 368 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false); 369 | ctx.fillStyle = shadow; 370 | ctx.fill(); 371 | 372 | // Draw background 373 | ctx.beginPath(); 374 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 375 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 376 | ctx.fillStyle = background; 377 | ctx.fill(); 378 | 379 | // Draw donut 380 | if (percentage > 0) { 381 | ctx.beginPath(); 382 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 383 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 384 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 385 | ctx.fillStyle = color; 386 | ctx.fill(); 387 | 388 | ctx.beginPath(); 389 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 390 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - donutWidth, -0.5 * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false); 391 | ctx.lineTo(canvas.width / 2, canvas.height / 2); 392 | ctx.fillStyle = background; 393 | ctx.fill(); 394 | } 395 | } 396 | 397 | setFaviconTag(canvas.toDataURL()); 398 | } 399 | }, { 400 | key: 'render', 401 | value: function render() { 402 | return null; 403 | } 404 | }]); 405 | return Donut; 406 | }(React__default.Component); 407 | 408 | Donut.propTypes = { 409 | donutWidth: PropTypes.number, 410 | percentage: PropTypes.number, 411 | color: PropTypes.string, 412 | background: PropTypes.string, 413 | shadow: PropTypes.string 414 | }; 415 | 416 | var Exception = function (_React$Component) { 417 | inherits(Exception, _React$Component); 418 | 419 | function Exception() { 420 | classCallCheck(this, Exception); 421 | return possibleConstructorReturn(this, (Exception.__proto__ || Object.getPrototypeOf(Exception)).apply(this, arguments)); 422 | } 423 | 424 | createClass(Exception, [{ 425 | key: 'componentDidMount', 426 | value: function componentDidMount() { 427 | this.drawFavicon(); 428 | } 429 | }, { 430 | key: 'drawFavicon', 431 | value: function drawFavicon() { 432 | var color = this.props.color; 433 | 434 | var canvas = getCanvas(); 435 | var ctx = canvas.getContext('2d'); 436 | 437 | ctx.clearRect(0, 0, canvas.width, canvas.height); 438 | 439 | // Draw background 440 | ctx.beginPath(); 441 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 442 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 443 | ctx.fillStyle = color; 444 | ctx.fill(); 445 | 446 | // Draw cross 447 | ctx.beginPath(); 448 | ctx.moveTo(canvas.width / 3, canvas.height / 3); 449 | ctx.lineTo(2 * canvas.width / 3, 2 * canvas.height / 3); 450 | ctx.lineWidth = 3; 451 | ctx.strokeStyle = '#fff'; 452 | ctx.stroke(); 453 | 454 | ctx.beginPath(); 455 | ctx.moveTo(canvas.width / 3, 2 * canvas.height / 3); 456 | ctx.lineTo(2 * canvas.width / 3, canvas.height / 3); 457 | ctx.lineWidth = 3; 458 | ctx.strokeStyle = '#fff'; 459 | ctx.stroke(); 460 | 461 | setFaviconTag(canvas.toDataURL()); 462 | } 463 | }, { 464 | key: 'render', 465 | value: function render() { 466 | return null; 467 | } 468 | }]); 469 | return Exception; 470 | }(React__default.Component); 471 | 472 | Exception.propTypes = { 473 | color: PropTypes.string 474 | }; 475 | 476 | Exception.defaultProps = { 477 | color: '#ff564e' 478 | }; 479 | 480 | var Success = function (_React$Component) { 481 | inherits(Success, _React$Component); 482 | 483 | function Success() { 484 | classCallCheck(this, Success); 485 | return possibleConstructorReturn(this, (Success.__proto__ || Object.getPrototypeOf(Success)).apply(this, arguments)); 486 | } 487 | 488 | createClass(Success, [{ 489 | key: 'componentDidMount', 490 | value: function componentDidMount() { 491 | this.drawFavicon(); 492 | } 493 | }, { 494 | key: 'drawFavicon', 495 | value: function drawFavicon() { 496 | var color = this.props.color; 497 | 498 | var canvas = getCanvas(); 499 | var ctx = canvas.getContext('2d'); 500 | 501 | if (ctx) { 502 | ctx.clearRect(0, 0, canvas.width, canvas.height); 503 | 504 | // Draw background 505 | ctx.beginPath(); 506 | ctx.moveTo(canvas.width / 2, canvas.height / 2); 507 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false); 508 | ctx.fillStyle = color; 509 | ctx.fill(); 510 | 511 | // Draw tick 512 | ctx.beginPath(); 513 | ctx.moveTo(canvas.width * 0.22, canvas.height * 0.5); 514 | ctx.lineTo(canvas.width * 0.45, canvas.height * 0.7); 515 | ctx.lineTo(canvas.width * 0.73, canvas.height * 0.3); 516 | ctx.lineWidth = 3; 517 | ctx.strokeStyle = '#fff'; 518 | ctx.stroke(); 519 | } 520 | 521 | setFaviconTag(canvas.toDataURL()); 522 | } 523 | }, { 524 | key: 'render', 525 | value: function render() { 526 | return null; 527 | } 528 | }]); 529 | return Success; 530 | }(React__default.Component); 531 | 532 | Success.propTypes = { 533 | color: PropTypes.string 534 | }; 535 | 536 | Success.defaultProps = { 537 | color: '#25c639' 538 | }; 539 | 540 | var LoadCon = function (_React$Component) { 541 | inherits(LoadCon, _React$Component); 542 | 543 | function LoadCon() { 544 | var _ref; 545 | 546 | var _temp, _this, _ret; 547 | 548 | classCallCheck(this, LoadCon); 549 | 550 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 551 | args[_key] = arguments[_key]; 552 | } 553 | 554 | return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = LoadCon.__proto__ || Object.getPrototypeOf(LoadCon)).call.apply(_ref, [this].concat(args))), _this), _this.state = { 555 | originalFaviconURL: null 556 | }, _this._renderFavicon = function () { 557 | switch (_this.props.type) { 558 | default: 559 | case 'pie': 560 | return React__default.createElement(Pie, _this.props); 561 | case 'donut': 562 | return React__default.createElement(Donut, _this.props); 563 | } 564 | }, _this._resetFavicon = function () { 565 | var originalFaviconURL = _this.state.originalFaviconURL; 566 | 567 | setFaviconTag(originalFaviconURL); 568 | }, _temp), possibleConstructorReturn(_this, _ret); 569 | } 570 | 571 | createClass(LoadCon, [{ 572 | key: 'componentDidMount', 573 | value: function componentDidMount() { 574 | this.setState({ 575 | originalFaviconURL: getFaviconURL() 576 | }); 577 | } 578 | }, { 579 | key: 'componentDidUpdate', 580 | value: function componentDidUpdate(prevProps) { 581 | var isPropsChanged = !reactFastCompare(this.props, prevProps); 582 | if (isPropsChanged) { 583 | if (this.props.status === 'normal') { 584 | this._resetFavicon(); 585 | } 586 | } 587 | } 588 | }, { 589 | key: 'render', 590 | value: function render() { 591 | var status = this.props.status; 592 | 593 | return React__default.createElement( 594 | NoSSR, 595 | null, 596 | status === 'active' && this._renderFavicon(), 597 | status === 'exception' && React__default.createElement(Exception, null), 598 | status === 'success' && React__default.createElement(Success, null) 599 | ); 600 | } 601 | }]); 602 | return LoadCon; 603 | }(React__default.Component); 604 | 605 | LoadCon.propTypes = { 606 | percentage: PropTypes.number.isRequired, 607 | type: PropTypes.oneOf(['pie', 'donut']), 608 | status: PropTypes.oneOf(['normal', 'active', 'exception', 'success']), 609 | color: PropTypes.string, 610 | background: PropTypes.string, 611 | shadow: PropTypes.string, 612 | donutWidth: PropTypes.number 613 | }; 614 | 615 | LoadCon.defaultProps = { 616 | percentage: 0, 617 | type: 'pie', 618 | status: 'normal', 619 | color: '#25c639', 620 | background: '#eee', 621 | shadow: '#fff', 622 | donutWidth: 8 623 | }; 624 | 625 | module.exports = LoadCon; 626 | //# sourceMappingURL=index.js.map 627 | -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sources":["../node_modules/react-fast-compare/index.js","../src/utils/NoSSR.js","../src/utils/index.js","../src/Favicons/Pie.js","../src/Favicons/Donut.js","../src/Favicons/Exception.js","../src/Favicons/Success.js","../src/index.js"],"sourcesContent":["'use strict';\n\nvar isArray = Array.isArray;\nvar keyList = Object.keys;\nvar hasProp = Object.prototype.hasOwnProperty;\nvar hasElementType = typeof Element !== 'undefined';\n\nfunction equal(a, b) {\n // fast-deep-equal index.js 2.0.1\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n var arrA = isArray(a)\n , arrB = isArray(b)\n , i\n , length\n , key;\n\n if (arrA && arrB) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n if (arrA != arrB) return false;\n\n var dateA = a instanceof Date\n , dateB = b instanceof Date;\n if (dateA != dateB) return false;\n if (dateA && dateB) return a.getTime() == b.getTime();\n\n var regexpA = a instanceof RegExp\n , regexpB = b instanceof RegExp;\n if (regexpA != regexpB) return false;\n if (regexpA && regexpB) return a.toString() == b.toString();\n\n var keys = keyList(a);\n length = keys.length;\n\n if (length !== keyList(b).length)\n return false;\n\n for (i = length; i-- !== 0;)\n if (!hasProp.call(b, keys[i])) return false;\n // end fast-deep-equal\n\n // start react-fast-compare\n // custom handling for DOM elements\n if (hasElementType && a instanceof Element && b instanceof Element)\n return a === b;\n\n // custom handling for React\n for (i = length; i-- !== 0;) {\n key = keys[i];\n if (key === '_owner' && a.$$typeof) {\n // React-specific: avoid traversing React elements' _owner.\n // _owner contains circular references\n // and is not needed when comparing the actual elements (and not their owners)\n // .$$typeof and ._store on just reasonable markers of a react element\n continue;\n } else {\n // all other properties should be traversed as usual\n if (!equal(a[key], b[key])) return false;\n }\n }\n // end react-fast-compare\n\n // fast-deep-equal index.js 2.0.1\n return true;\n }\n\n return a !== a && b !== b;\n}\n// end fast-deep-equal\n\nmodule.exports = function exportedEqual(a, b) {\n try {\n return equal(a, b);\n } catch (error) {\n if ((error.message && error.message.match(/stack|recursion/i)) || (error.number === -2146828260)) {\n // warn on circular references, don't crash\n // browsers give this different errors name and messages:\n // chrome/safari: \"RangeError\", \"Maximum call stack size exceeded\"\n // firefox: \"InternalError\", too much recursion\"\n // edge: \"Error\", \"Out of stack space\"\n console.warn('Warning: react-fast-compare does not handle circular references.', error.name, error.message);\n return false;\n }\n // some other error. we should definitely know about these\n throw error;\n }\n};\n","import React, { Component } from 'react'\n\nconst DefaultOnSSR = () => ()\n\nclass NoSSR extends Component {\n state = {\n canRender: false\n }\n\n componentDidMount() {\n this.setState({ canRender: true })\n }\n\n render() {\n const { children, onSSR = } = this.props\n\n return (\n \n {this.state.canRender ? children : onSSR}\n \n )\n }\n}\n\nexport default NoSSR\n","const isUA = (browser) => {\n const agent = navigator.userAgent.toLowerCase()\n return agent.indexOf(browser) !== 1\n}\n\nexport const getIsRetina = () => {\n return window.devicePixelRatio > 1\n}\n\nexport const getBrowser = () => {\n if (isUA('msie')) {\n return 'ie'\n } else if (isUA('chrome')) {\n return 'chrome'\n } else if (isUA('chrome') || isUA('safari')) {\n return 'webkit'\n } else if (isUA('safari') && !isUA('chrome')) {\n return 'safari'\n } else if (isUA('mozilla') && !isUA('chrome') && !isUA('safari')) {\n return 'mozilla'\n }\n}\n\nexport const getFaviconURL = () => {\n const links = document.getElementsByTagName('link')\n let tag = null\n\n for (let i = 0, l = links.length; i < l; i++) {\n if (links[i].getAttribute('rel') === 'icon'\n || links[i].getAttribute('rel') === 'shortcut icon') {\n tag = links[i]\n }\n }\n\n return tag ? tag.getAttribute('href') : '/favicon.ico'\n}\n\nexport const removeFaviconTag = () => {\n const links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0)\n const head = document.getElementsByTagName('head')[0]\n\n for (let i = 0, l = links.length; i < l; i++) {\n if (links[i].getAttribute('rel') === 'icon'\n || links[i].getAttribute('rel') === 'shortcut icon') {\n head.removeChild(links[i])\n }\n }\n}\n\nexport const setFaviconTag = (url) => {\n removeFaviconTag()\n\n const link = document.createElement('link')\n link.type = 'image/x-icon'\n link.rel = 'icon'\n link.href = url\n\n document.getElementsByTagName('head')[0].appendChild(link)\n}\n\nexport const getCanvas = function () {\n const canvas = document.createElement(\"canvas\")\n if (getIsRetina()) {\n canvas.width = 32\n canvas.height = 32\n } else {\n canvas.width = 16\n canvas.height = 16\n }\n\n return canvas\n}\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Pie extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n this.drawFavicon()\n }\n }\n\n drawFavicon () {\n const { percentage, color, background, shadow } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw shadow\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false)\n ctx.fillStyle = shadow\n ctx.fill()\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = background\n ctx.fill()\n\n // Draw pie\n if (percentage > 0) {\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = color\n ctx.fill()\n }\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nPie.propTypes = {\n percentage: PropTypes.number,\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n}\n\nexport default Pie\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Donut extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n this.drawFavicon()\n }\n }\n\n drawFavicon () {\n const { donutWidth, percentage, color, background, shadow } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw shadow\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false)\n ctx.fillStyle = shadow\n ctx.fill()\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = background\n ctx.fill()\n\n // Draw donut\n if (percentage > 0) {\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = color\n ctx.fill()\n\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - donutWidth, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false)\n ctx.lineTo(canvas.width / 2, canvas.height / 2)\n ctx.fillStyle = background\n ctx.fill()\n }\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nDonut.propTypes = {\n donutWidth: PropTypes.number,\n percentage: PropTypes.number,\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n}\n\nexport default Donut\n","import React from 'react'\nimport PropTypes from 'prop-types'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Exception extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n drawFavicon () {\n const { color } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = color\n ctx.fill()\n\n // Draw cross\n ctx.beginPath()\n ctx.moveTo(canvas.width / 3, canvas.height / 3)\n ctx.lineTo(2 * canvas.width / 3, 2 * canvas.height / 3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n\n ctx.beginPath()\n ctx.moveTo(canvas.width / 3, 2 * canvas.height / 3)\n ctx.lineTo(2 * canvas.width / 3, canvas.height / 3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nException.propTypes = {\n color: PropTypes.string,\n}\n\nException.defaultProps = {\n color: '#ff564e'\n}\n\nexport default Exception\n","import React from 'react'\nimport PropTypes from 'prop-types'\n\nimport { getCanvas, setFaviconTag } from '../utils'\n\nclass Success extends React.Component {\n componentDidMount () {\n this.drawFavicon()\n }\n\n drawFavicon () {\n const { color } = this.props\n const canvas = getCanvas()\n const ctx = canvas.getContext('2d')\n\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n\n // Draw background\n ctx.beginPath()\n ctx.moveTo(canvas.width / 2, canvas.height / 2)\n ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false)\n ctx.fillStyle = color\n ctx.fill()\n\n // Draw tick\n ctx.beginPath()\n ctx.moveTo(canvas.width * 0.22, canvas.height * 0.5)\n ctx.lineTo(canvas.width * 0.45, canvas.height * 0.7)\n ctx.lineTo(canvas.width * 0.73, canvas.height * 0.3)\n ctx.lineWidth = 3\n ctx.strokeStyle = '#fff'\n ctx.stroke()\n }\n\n setFaviconTag(canvas.toDataURL())\n }\n\n render () {\n return (null)\n }\n}\n\nSuccess.propTypes = {\n color: PropTypes.string,\n}\n\nSuccess.defaultProps = {\n color: '#25c639'\n}\n\nexport default Success\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport isEqual from 'react-fast-compare'\n\nimport NoSSR from './utils/NoSSR'\nimport { getFaviconURL, setFaviconTag } from './utils'\n\nimport PieCon from './Favicons/Pie'\nimport DonutCon from './Favicons/Donut'\nimport ExceptionCon from './Favicons/Exception'\nimport SuccessCon from './Favicons/Success'\n\nclass LoadCon extends React.Component {\n state = {\n originalFaviconURL: null\n }\n\n componentDidMount () {\n this.setState({\n originalFaviconURL: getFaviconURL()\n })\n }\n\n componentDidUpdate (prevProps) {\n const isPropsChanged = !isEqual(this.props, prevProps)\n if (isPropsChanged) {\n if (this.props.status === 'normal') {\n this._resetFavicon()\n }\n }\n }\n\n _renderFavicon = () => {\n switch (this.props.type) {\n default:\n case 'pie':\n return \n case 'donut':\n return \n }\n }\n\n _resetFavicon = () => {\n const { originalFaviconURL } = this.state\n setFaviconTag(originalFaviconURL)\n }\n\n render() {\n const { status } = this.props\n return (\n \n {status === 'active' && this._renderFavicon()}\n {status === 'exception' && }\n {status === 'success' && }\n \n )\n }\n}\n\nLoadCon.propTypes = {\n percentage: PropTypes.number.isRequired,\n type: PropTypes.oneOf(['pie', 'donut']),\n status: PropTypes.oneOf(['normal', 'active', 'exception', 'success']),\n color: PropTypes.string,\n background: PropTypes.string,\n shadow: PropTypes.string,\n donutWidth: PropTypes.number,\n}\n\nLoadCon.defaultProps = {\n percentage: 0,\n type: 'pie',\n status: 'normal',\n color: '#25c639',\n background: '#eee',\n shadow: '#fff',\n donutWidth: 8,\n}\n\nexport default LoadCon\n"],"names":["DefaultOnSSR","React","NoSSR","state","setState","canRender","props","children","onSSR","Component","getIsRetina","window","devicePixelRatio","getFaviconURL","links","document","getElementsByTagName","tag","i","l","length","getAttribute","removeFaviconTag","Array","prototype","slice","call","head","removeChild","setFaviconTag","url","link","createElement","type","rel","href","appendChild","getCanvas","canvas","width","height","Pie","drawFavicon","prevProps","isPropsChanged","isEqual","percentage","color","background","shadow","ctx","getContext","clearRect","beginPath","moveTo","arc","Math","min","PI","fillStyle","fill","lineTo","toDataURL","propTypes","PropTypes","number","string","Donut","donutWidth","Exception","lineWidth","strokeStyle","stroke","defaultProps","Success","LoadCon","_renderFavicon","PieCon","DonutCon","_resetFavicon","originalFaviconURL","status","ExceptionCon","SuccessCon","isRequired","oneOf"],"mappings":"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"} -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-loadcon-example", 3 | "homepage": "https://foreseaz.github.io/react-loadcon", 4 | "version": "0.0.0", 5 | "license": "MIT", 6 | "private": true, 7 | "dependencies": { 8 | "prop-types": "^15.6.2", 9 | "react": "^16.4.1", 10 | "react-dom": "^16.4.1", 11 | "react-loadcon": "^0.1.0", 12 | "react-markdown": "^4.0.6", 13 | "react-scripts": "^1.1.4", 14 | "react-syntax-highlighter": "^10.2.1" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test --env=jsdom", 20 | "eject": "react-scripts eject" 21 | }, 22 | "devDependencies": {} 23 | } 24 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreseaz/react-loadcon/770ccb24c25d63714a4279f932c3ed1ca3ae0624/example/public/favicon.ico -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | React LoadCon 14 | 15 | 16 | 17 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "react-loadcon", 3 | "name": "react-loadcon", 4 | "start_url": "./index.html", 5 | "display": "standalone", 6 | "theme_color": "#000000", 7 | "background_color": "#ffffff" 8 | } 9 | -------------------------------------------------------------------------------- /example/ship.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env sh 3 | 4 | # abort on errors 5 | set -e 6 | 7 | # build 8 | yarn build 9 | 10 | # navigate into the build output directory 11 | cd build 12 | 13 | # if you are deploying to a custom domain 14 | # echo 'domain.io' > CNAME 15 | 16 | git init 17 | git add -A 18 | git commit -m 'ship: deployment gh-page' 19 | 20 | # if you are deploying to https://.github.io 21 | # git push -f git@github.com:/.github.io.git master 22 | 23 | # if you are deploying to https://.github.io/ 24 | git push -f https://github.com/foreseaz/react-loadcon.git master:gh-pages 25 | 26 | 27 | cd - 28 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | import ReactMarkdown from 'react-markdown' 4 | import SyntaxHighlighter from 'react-syntax-highlighter' 5 | import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs' 6 | 7 | import LoadCon from 'react-loadcon' 8 | 9 | export default class App extends Component { 10 | state = { 11 | status: 'normal', 12 | type: 'pie', 13 | percentage: 0 14 | } 15 | 16 | handleTypeChange = (e) => { 17 | this.setState({ type: e.target.value }) 18 | e.preventDefault() 19 | } 20 | 21 | asyncLoading = (hasError = false) => { 22 | this.setState({ status: 'active', percentage: 0 }) 23 | 24 | const promise = new Promise((resolve, reject) => { 25 | let inter = setInterval(() => { 26 | const { percentage } = this.state 27 | 28 | let p = percentage + Math.random() * 1000 % 10 29 | p = p >= 100 ? 100 : p 30 | if (hasError && p > 70) { 31 | clearInterval(inter) 32 | reject() 33 | } 34 | if (p === 100) { 35 | clearInterval(inter) 36 | this.setState({ status: 'normal' }) 37 | resolve() 38 | } 39 | 40 | this.setState({ percentage: p }) 41 | }, 200) 42 | }) 43 | 44 | return promise 45 | } 46 | 47 | raiseException = () => { 48 | this.asyncLoading(true).catch(e => { 49 | this.setState({ status: 'exception' }) 50 | setTimeout(() => { 51 | this.setState({ status: 'normal' }) 52 | }, 1500) 53 | }) 54 | } 55 | 56 | raiseSuccess = () => { 57 | this.asyncLoading().then(() => { 58 | this.setState({ status: 'success' }) 59 | setTimeout(() => { 60 | this.setState({ status: 'normal' }) 61 | }, 1500) 62 | }) 63 | } 64 | 65 | updateStatus = (status) => { 66 | this.setState({ status }) 67 | } 68 | 69 | normalDoc = () => `\ 70 | import React, { Component } from 'react' 71 | import LoadCon from 'react-loadcon' 72 | 73 | export default class ExampleComponent extends Component { 74 | state = { 75 | percentage: 0, // isRequired 76 | status: 'normal', // oneOf(['normal', 'active', 'exception', 'success']) 77 | type: 'pie', // oneOf(['pie', 'donut']) 78 | } 79 | 80 | componentDidMount () { 81 | this.apiCall() 82 | } 83 | 84 | apiCall = () => { 85 | this.setState({ status: 'active' }) 86 | fetch(url) 87 | .then(res => return res.json()) 88 | .then(data => { 89 | // normal loading 90 | this.setState({ status: 'normal' }) 91 | 92 | // loading with success 93 | this.setState({ status: 'success' }) 94 | setTimeout(() => { 95 | this.setState({ status: 'normal' }) 96 | }, 1500) 97 | }) 98 | .catch(e => { 99 | this.setState({ status: 'exception' }) 100 | setTimeout(() => { 101 | this.setState({ status: 'normal' }) 102 | }, 1500) 103 | }) 104 | } 105 | 106 | render () { 107 | return ( 108 | 113 | ) 114 | } 115 | }\ 116 | ` 117 | 118 | propsExplain = () => `\ 119 | ## Props 120 | 121 | - \`percentage: PropTypes.number.isRequired\`, the percentage of loading progress for LoadCon. 122 | - \`type: PropTypes.oneOf(['pie', 'donut'])\`, the theme of LoadCon, now has \`PieCon\` and \`DonutCon\`, and more themes will be added soon. 123 | - \`status: PropTypes.oneOf(['normal', 'active', 'exception', 'success'])\`, load status of LoadCon, \`normal\` reset to default favicon, \`active\` set LoadCon according to the type prop, \`exception\` set ErrorCon and \`success\` set SuccessCon. 124 | - \`color: PropTypes.string\`, color of loading indicator in hash format, default is \`#25c639\`. 125 | - \`background: PropTypes.string\`, color of background in hash format, default is \`#eeeeee\`. 126 | - \`shadow: PropTypes.string\`, color of 2 pixals border in hash format, default is \`#ffffff\`. 127 | - \`donutWidth: PropTypes.number\`, width of DonutCon indicator in number, default is \`8px\`. 128 | ` 129 | 130 | render () { 131 | return ( 132 |
133 | 138 |
139 | React LoadCon 140 | 148 | Star 149 | 150 |
151 |
152 |
153 | 154 |
155 | 159 |
160 |
161 |
162 | 167 | 173 | 179 |
180 |
181 | 186 | {this.normalDoc()} 187 | 188 |
189 | 190 |
191 | 192 |
193 |
194 | 195 |
196 | Foreseaz | 2019 197 |
198 |
199 | ) 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: 'Montserrat', sans-serif; 5 | background: #fff7e5; 6 | } 7 | ::selection { 8 | background-color: #79FFE1; 9 | color: #000; 10 | } 11 | .container { 12 | width: 960px; 13 | padding: 50px 100px; 14 | margin: 0 auto; 15 | } 16 | .nav { 17 | padding: 30px 0; 18 | display: flex; 19 | justify-content: space-between; 20 | } 21 | .nav .title { 22 | /* color: #bf2f4c; */ 23 | font-weight: 600; 24 | font-size: 40px; 25 | } 26 | .select-wrapper { 27 | padding: 0; 28 | margin-left: 10px; 29 | transform: translateY(10px); 30 | display: inline-block; 31 | border: 1px solid #bf2f4c; 32 | border-radius: 5px; 33 | width: 80px; 34 | overflow: hidden; 35 | background-color: #fff; 36 | box-shadow: rgba(0, 0, 0, 0.12) 0px 5px 10px; 37 | } 38 | .select-wrapper select { 39 | font-family: 'Montserrat', sans-serif; 40 | font-weight: 600; 41 | font-size: 14px; 42 | color: #bf2f4c; 43 | padding: 5px; 44 | width: 100%; 45 | border: none; 46 | box-shadow: none; 47 | background-color: #fff; 48 | background-image: none; 49 | -webkit-appearance: none; 50 | -moz-appearance: none; 51 | appearance: none; 52 | } 53 | .select-wrapper select:focus { 54 | outline: none; 55 | } 56 | 57 | .btns { 58 | padding: 50px 0 20px; 59 | } 60 | button { 61 | align-items: center; 62 | color: #fff; 63 | height: 40px; 64 | width: 175px; 65 | font-size: 12px; 66 | justify-content: center; 67 | text-transform: uppercase; 68 | cursor: pointer; 69 | text-align: center; 70 | user-select: none; 71 | font-weight: 100; 72 | position: relative; 73 | white-space: nowrap; 74 | line-height: 0; 75 | box-shadow: rgba(0, 0, 0, 0.12) 0px 5px 10px; 76 | background: rgb(0, 122, 255); 77 | padding: 0px 25px; 78 | outline: none; 79 | border-width: 1px; 80 | border-style: solid; 81 | border-color: rgb(0, 122, 255); 82 | border-image: initial; 83 | overflow: hidden; 84 | transition: all 0.15s ease 0s; 85 | border-radius: 5px; 86 | } 87 | button.success { 88 | background: #25c639; 89 | border-color: #25c639; 90 | } 91 | button.error { 92 | background: #ff564e; 93 | border-color: #ff564e; 94 | } 95 | button:hover { 96 | box-shadow: rgba(0, 0, 0, 0.16) 0px 7px 20px; 97 | transform: translateY(-1px); 98 | } 99 | button + button { 100 | margin-left: 15px; 101 | } 102 | .star { 103 | margin-top: 100px; 104 | } 105 | .author { 106 | margin-top: 30px; 107 | color: #aaa; 108 | font-size: 12px; 109 | } 110 | .markdown { 111 | font-family: sans-serif; 112 | } 113 | .markdown li { 114 | line-height: 1.4em; 115 | } 116 | .markdown code { 117 | background: white; 118 | border: 1px solid #ccc; 119 | padding: 1px 5px; 120 | border-radius: 5px; 121 | } 122 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import './index.css' 5 | import App from './App' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | -------------------------------------------------------------------------------- /example/yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /usr/local/bin/node /Users/Foresea/.yarn/bin/yarn.js 3 | 4 | PATH: 5 | /Users/Foresea/.npm-packages/bin:/Users/Foresea/.rbenv/shims:/Users/Foresea/google-cloud-sdk/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/texbin:/Users/Foresea/bin:/Users/Foresea/.yarn/bin:/Users/Foresea/go/bin:/usr/local/go/bin 6 | 7 | Yarn version: 8 | 0.24.6 9 | 10 | Node version: 11 | 11.6.0 12 | 13 | Platform: 14 | darwin x64 15 | 16 | npm manifest: 17 | { 18 | "name": "react-loadcon-example", 19 | "homepage": "https://foreseaz.github.io/react-loadcon", 20 | "version": "0.0.0", 21 | "license": "MIT", 22 | "private": true, 23 | "dependencies": { 24 | "prop-types": "^15.6.2", 25 | "react": "^16.4.1", 26 | "react-dom": "^16.4.1", 27 | "react-scripts": "^1.1.4", 28 | "react-loadcon": "link:../dist/index.es.js" 29 | }, 30 | "scripts": { 31 | "start": "react-scripts start", 32 | "build": "react-scripts build", 33 | "test": "react-scripts test --env=jsdom", 34 | "eject": "react-scripts eject" 35 | } 36 | } 37 | 38 | yarn manifest: 39 | No manifest 40 | 41 | Lockfile: 42 | No lockfile 43 | 44 | Trace: 45 | Error: https://registry.yarnpkg.com/react-loadcon: Not found 46 | at Request.params.callback [as _callback] (/Users/Foresea/.yarn/lib/yarn-cli.js:56255:18) 47 | at Request.self.callback (/Users/Foresea/.yarn/lib/yarn-cli.js:107854:22) 48 | at Request.emit (events.js:188:13) 49 | at Request. (/Users/Foresea/.yarn/lib/yarn-cli.js:108837:10) 50 | at Request.emit (events.js:188:13) 51 | at IncomingMessage. (/Users/Foresea/.yarn/lib/yarn-cli.js:108757:12) 52 | at Object.onceWrapper (events.js:276:13) 53 | at IncomingMessage.emit (events.js:193:15) 54 | at endReadableNT (_stream_readable.js:1129:12) 55 | at process.internalTickCallback (internal/process/next_tick.js:72:19) 56 | -------------------------------------------------------------------------------- /imgs/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreseaz/react-loadcon/770ccb24c25d63714a4279f932c3ed1ca3ae0624/imgs/intro.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-loadcon", 3 | "version": "0.1.1", 4 | "description": "React component for manipulating the favicon, for loading or progress.", 5 | "author": "foreseaz", 6 | "license": "MIT", 7 | "repository": "foreseaz/react-loadcon", 8 | "main": "dist/index.js", 9 | "module": "dist/index.es.js", 10 | "jsnext:main": "dist/index.es.js", 11 | "engines": { 12 | "node": ">=8", 13 | "npm": ">=5" 14 | }, 15 | "scripts": { 16 | "test": "cross-env CI=1 react-scripts test --env=jsdom", 17 | "test:watch": "react-scripts test --env=jsdom", 18 | "build": "rollup -c", 19 | "start": "rollup -c -w", 20 | "prepare": "yarn run build", 21 | "predeploy": "cd example && yarn install && yarn run build", 22 | "deploy": "gh-pages -d example/build" 23 | }, 24 | "peerDependencies": { 25 | "prop-types": "^15.5.4", 26 | "react": "^15.0.0 || ^16.0.0", 27 | "react-dom": "^15.0.0 || ^16.0.0" 28 | }, 29 | "devDependencies": { 30 | "@svgr/rollup": "^2.4.1", 31 | "babel-core": "^6.26.3", 32 | "babel-eslint": "^8.2.5", 33 | "babel-plugin-external-helpers": "^6.22.0", 34 | "babel-preset-env": "^1.7.0", 35 | "babel-preset-react": "^6.24.1", 36 | "babel-preset-stage-0": "^6.24.1", 37 | "cross-env": "^5.1.4", 38 | "eslint": "^5.0.1", 39 | "eslint-config-standard": "^11.0.0", 40 | "eslint-config-standard-react": "^6.0.0", 41 | "eslint-plugin-import": "^2.13.0", 42 | "eslint-plugin-node": "^7.0.1", 43 | "eslint-plugin-promise": "^4.0.0", 44 | "eslint-plugin-react": "^7.10.0", 45 | "eslint-plugin-standard": "^3.1.0", 46 | "gh-pages": "^1.2.0", 47 | "react": "^16.4.1", 48 | "react-dom": "^16.4.1", 49 | "react-scripts": "^1.1.4", 50 | "rollup": "^0.64.1", 51 | "rollup-plugin-babel": "^3.0.7", 52 | "rollup-plugin-commonjs": "^9.1.3", 53 | "rollup-plugin-node-resolve": "^3.3.0", 54 | "rollup-plugin-peer-deps-external": "^2.2.0", 55 | "rollup-plugin-postcss": "^1.6.2", 56 | "rollup-plugin-url": "^1.4.0" 57 | }, 58 | "files": [ 59 | "dist" 60 | ], 61 | "dependencies": { 62 | "react-fast-compare": "^2.0.4" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import external from 'rollup-plugin-peer-deps-external' 4 | import postcss from 'rollup-plugin-postcss' 5 | import resolve from 'rollup-plugin-node-resolve' 6 | import url from 'rollup-plugin-url' 7 | import svgr from '@svgr/rollup' 8 | 9 | import pkg from './package.json' 10 | 11 | export default { 12 | input: 'src/index.js', 13 | output: [ 14 | { 15 | file: pkg.main, 16 | format: 'cjs', 17 | sourcemap: true 18 | }, 19 | { 20 | file: pkg.module, 21 | format: 'es', 22 | sourcemap: true 23 | } 24 | ], 25 | plugins: [ 26 | external(), 27 | postcss({ 28 | modules: true 29 | }), 30 | url(), 31 | svgr(), 32 | babel({ 33 | exclude: 'node_modules/**', 34 | plugins: [ 'external-helpers' ] 35 | }), 36 | resolve(), 37 | commonjs() 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/Favicons/Donut.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import isEqual from 'react-fast-compare' 4 | 5 | import { getCanvas, setFaviconTag } from '../utils' 6 | 7 | class Donut extends React.Component { 8 | componentDidMount () { 9 | this.drawFavicon() 10 | } 11 | 12 | componentDidUpdate (prevProps) { 13 | const isPropsChanged = !isEqual(this.props, prevProps) 14 | if (isPropsChanged) { 15 | this.drawFavicon() 16 | } 17 | } 18 | 19 | drawFavicon () { 20 | const { donutWidth, percentage, color, background, shadow } = this.props 21 | const canvas = getCanvas() 22 | const ctx = canvas.getContext('2d') 23 | 24 | if (ctx) { 25 | ctx.clearRect(0, 0, canvas.width, canvas.height) 26 | 27 | // Draw shadow 28 | ctx.beginPath() 29 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 30 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false) 31 | ctx.fillStyle = shadow 32 | ctx.fill() 33 | 34 | // Draw background 35 | ctx.beginPath() 36 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 37 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false) 38 | ctx.fillStyle = background 39 | ctx.fill() 40 | 41 | // Draw donut 42 | if (percentage > 0) { 43 | ctx.beginPath() 44 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 45 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false) 46 | ctx.lineTo(canvas.width / 2, canvas.height / 2) 47 | ctx.fillStyle = color 48 | ctx.fill() 49 | 50 | ctx.beginPath() 51 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 52 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - donutWidth, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false) 53 | ctx.lineTo(canvas.width / 2, canvas.height / 2) 54 | ctx.fillStyle = background 55 | ctx.fill() 56 | } 57 | } 58 | 59 | setFaviconTag(canvas.toDataURL()) 60 | } 61 | 62 | render () { 63 | return (null) 64 | } 65 | } 66 | 67 | Donut.propTypes = { 68 | donutWidth: PropTypes.number, 69 | percentage: PropTypes.number, 70 | color: PropTypes.string, 71 | background: PropTypes.string, 72 | shadow: PropTypes.string, 73 | } 74 | 75 | export default Donut 76 | -------------------------------------------------------------------------------- /src/Favicons/Exception.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import { getCanvas, setFaviconTag } from '../utils' 5 | 6 | class Exception extends React.Component { 7 | componentDidMount () { 8 | this.drawFavicon() 9 | } 10 | 11 | drawFavicon () { 12 | const { color } = this.props 13 | const canvas = getCanvas() 14 | const ctx = canvas.getContext('2d') 15 | 16 | ctx.clearRect(0, 0, canvas.width, canvas.height) 17 | 18 | // Draw background 19 | ctx.beginPath() 20 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 21 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false) 22 | ctx.fillStyle = color 23 | ctx.fill() 24 | 25 | // Draw cross 26 | ctx.beginPath() 27 | ctx.moveTo(canvas.width / 3, canvas.height / 3) 28 | ctx.lineTo(2 * canvas.width / 3, 2 * canvas.height / 3) 29 | ctx.lineWidth = 3 30 | ctx.strokeStyle = '#fff' 31 | ctx.stroke() 32 | 33 | ctx.beginPath() 34 | ctx.moveTo(canvas.width / 3, 2 * canvas.height / 3) 35 | ctx.lineTo(2 * canvas.width / 3, canvas.height / 3) 36 | ctx.lineWidth = 3 37 | ctx.strokeStyle = '#fff' 38 | ctx.stroke() 39 | 40 | setFaviconTag(canvas.toDataURL()) 41 | } 42 | 43 | render () { 44 | return (null) 45 | } 46 | } 47 | 48 | Exception.propTypes = { 49 | color: PropTypes.string, 50 | } 51 | 52 | Exception.defaultProps = { 53 | color: '#ff564e' 54 | } 55 | 56 | export default Exception 57 | -------------------------------------------------------------------------------- /src/Favicons/Pie.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import isEqual from 'react-fast-compare' 4 | 5 | import { getCanvas, setFaviconTag } from '../utils' 6 | 7 | class Pie extends React.Component { 8 | componentDidMount () { 9 | this.drawFavicon() 10 | } 11 | 12 | componentDidUpdate (prevProps) { 13 | const isPropsChanged = !isEqual(this.props, prevProps) 14 | if (isPropsChanged) { 15 | this.drawFavicon() 16 | } 17 | } 18 | 19 | drawFavicon () { 20 | const { percentage, color, background, shadow } = this.props 21 | const canvas = getCanvas() 22 | const ctx = canvas.getContext('2d') 23 | 24 | if (ctx) { 25 | ctx.clearRect(0, 0, canvas.width, canvas.height) 26 | 27 | // Draw shadow 28 | ctx.beginPath() 29 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 30 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false) 31 | ctx.fillStyle = shadow 32 | ctx.fill() 33 | 34 | // Draw background 35 | ctx.beginPath() 36 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 37 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false) 38 | ctx.fillStyle = background 39 | ctx.fill() 40 | 41 | // Draw pie 42 | if (percentage > 0) { 43 | ctx.beginPath() 44 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 45 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false) 46 | ctx.lineTo(canvas.width / 2, canvas.height / 2) 47 | ctx.fillStyle = color 48 | ctx.fill() 49 | } 50 | } 51 | 52 | setFaviconTag(canvas.toDataURL()) 53 | } 54 | 55 | render () { 56 | return (null) 57 | } 58 | } 59 | 60 | Pie.propTypes = { 61 | percentage: PropTypes.number, 62 | color: PropTypes.string, 63 | background: PropTypes.string, 64 | shadow: PropTypes.string, 65 | } 66 | 67 | export default Pie 68 | -------------------------------------------------------------------------------- /src/Favicons/Success.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import { getCanvas, setFaviconTag } from '../utils' 5 | 6 | class Success extends React.Component { 7 | componentDidMount () { 8 | this.drawFavicon() 9 | } 10 | 11 | drawFavicon () { 12 | const { color } = this.props 13 | const canvas = getCanvas() 14 | const ctx = canvas.getContext('2d') 15 | 16 | if (ctx) { 17 | ctx.clearRect(0, 0, canvas.width, canvas.height) 18 | 19 | // Draw background 20 | ctx.beginPath() 21 | ctx.moveTo(canvas.width / 2, canvas.height / 2) 22 | ctx.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false) 23 | ctx.fillStyle = color 24 | ctx.fill() 25 | 26 | // Draw tick 27 | ctx.beginPath() 28 | ctx.moveTo(canvas.width * 0.22, canvas.height * 0.5) 29 | ctx.lineTo(canvas.width * 0.45, canvas.height * 0.7) 30 | ctx.lineTo(canvas.width * 0.73, canvas.height * 0.3) 31 | ctx.lineWidth = 3 32 | ctx.strokeStyle = '#fff' 33 | ctx.stroke() 34 | } 35 | 36 | setFaviconTag(canvas.toDataURL()) 37 | } 38 | 39 | render () { 40 | return (null) 41 | } 42 | } 43 | 44 | Success.propTypes = { 45 | color: PropTypes.string, 46 | } 47 | 48 | Success.defaultProps = { 49 | color: '#25c639' 50 | } 51 | 52 | export default Success 53 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import isEqual from 'react-fast-compare' 4 | 5 | import NoSSR from './utils/NoSSR' 6 | import { getFaviconURL, setFaviconTag } from './utils' 7 | 8 | import PieCon from './Favicons/Pie' 9 | import DonutCon from './Favicons/Donut' 10 | import ExceptionCon from './Favicons/Exception' 11 | import SuccessCon from './Favicons/Success' 12 | 13 | class LoadCon extends React.Component { 14 | state = { 15 | originalFaviconURL: null 16 | } 17 | 18 | componentDidMount () { 19 | this.setState({ 20 | originalFaviconURL: getFaviconURL() 21 | }) 22 | } 23 | 24 | componentDidUpdate (prevProps) { 25 | const isPropsChanged = !isEqual(this.props, prevProps) 26 | if (isPropsChanged) { 27 | if (this.props.status === 'normal') { 28 | this._resetFavicon() 29 | } 30 | } 31 | } 32 | 33 | _renderFavicon = () => { 34 | switch (this.props.type) { 35 | default: 36 | case 'pie': 37 | return 38 | case 'donut': 39 | return 40 | } 41 | } 42 | 43 | _resetFavicon = () => { 44 | const { originalFaviconURL } = this.state 45 | setFaviconTag(originalFaviconURL) 46 | } 47 | 48 | render() { 49 | const { status } = this.props 50 | return ( 51 | 52 | {status === 'active' && this._renderFavicon()} 53 | {status === 'exception' && } 54 | {status === 'success' && } 55 | 56 | ) 57 | } 58 | } 59 | 60 | LoadCon.propTypes = { 61 | percentage: PropTypes.number.isRequired, 62 | type: PropTypes.oneOf(['pie', 'donut']), 63 | status: PropTypes.oneOf(['normal', 'active', 'exception', 'success']), 64 | color: PropTypes.string, 65 | background: PropTypes.string, 66 | shadow: PropTypes.string, 67 | donutWidth: PropTypes.number, 68 | } 69 | 70 | LoadCon.defaultProps = { 71 | percentage: 0, 72 | type: 'pie', 73 | status: 'normal', 74 | color: '#25c639', 75 | background: '#eee', 76 | shadow: '#fff', 77 | donutWidth: 8, 78 | } 79 | 80 | export default LoadCon 81 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* add css styles here (optional) */ 2 | 3 | .test { 4 | display: inline-block; 5 | margin: 2em auto; 6 | border: 2px solid #000; 7 | font-size: 2em; 8 | } 9 | -------------------------------------------------------------------------------- /src/test.js: -------------------------------------------------------------------------------- 1 | import ExampleComponent from './' 2 | 3 | describe('ExampleComponent', () => { 4 | it('is truthy', () => { 5 | expect(ExampleComponent).toBeTruthy() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /src/utils/NoSSR.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | const DefaultOnSSR = () => () 4 | 5 | class NoSSR extends Component { 6 | state = { 7 | canRender: false 8 | } 9 | 10 | componentDidMount() { 11 | this.setState({ canRender: true }) 12 | } 13 | 14 | render() { 15 | const { children, onSSR = } = this.props 16 | 17 | return ( 18 | 19 | {this.state.canRender ? children : onSSR} 20 | 21 | ) 22 | } 23 | } 24 | 25 | export default NoSSR 26 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | const isUA = (browser) => { 2 | const agent = navigator.userAgent.toLowerCase() 3 | return agent.indexOf(browser) !== 1 4 | } 5 | 6 | export const getIsRetina = () => { 7 | return window.devicePixelRatio > 1 8 | } 9 | 10 | export const getBrowser = () => { 11 | if (isUA('msie')) { 12 | return 'ie' 13 | } else if (isUA('chrome')) { 14 | return 'chrome' 15 | } else if (isUA('chrome') || isUA('safari')) { 16 | return 'webkit' 17 | } else if (isUA('safari') && !isUA('chrome')) { 18 | return 'safari' 19 | } else if (isUA('mozilla') && !isUA('chrome') && !isUA('safari')) { 20 | return 'mozilla' 21 | } 22 | } 23 | 24 | export const getFaviconURL = () => { 25 | const links = document.getElementsByTagName('link') 26 | let tag = null 27 | 28 | for (let i = 0, l = links.length; i < l; i++) { 29 | if (links[i].getAttribute('rel') === 'icon' 30 | || links[i].getAttribute('rel') === 'shortcut icon') { 31 | tag = links[i] 32 | } 33 | } 34 | 35 | return tag ? tag.getAttribute('href') : '/favicon.ico' 36 | } 37 | 38 | export const removeFaviconTag = () => { 39 | const links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0) 40 | const head = document.getElementsByTagName('head')[0] 41 | 42 | for (let i = 0, l = links.length; i < l; i++) { 43 | if (links[i].getAttribute('rel') === 'icon' 44 | || links[i].getAttribute('rel') === 'shortcut icon') { 45 | head.removeChild(links[i]) 46 | } 47 | } 48 | } 49 | 50 | export const setFaviconTag = (url) => { 51 | removeFaviconTag() 52 | 53 | const link = document.createElement('link') 54 | link.type = 'image/x-icon' 55 | link.rel = 'icon' 56 | link.href = url 57 | 58 | document.getElementsByTagName('head')[0].appendChild(link) 59 | } 60 | 61 | export const getCanvas = function () { 62 | const canvas = document.createElement("canvas") 63 | if (getIsRetina()) { 64 | canvas.width = 32 65 | canvas.height = 32 66 | } else { 67 | canvas.width = 16 68 | canvas.height = 16 69 | } 70 | 71 | return canvas 72 | } 73 | --------------------------------------------------------------------------------