├── .babelrc ├── .bithoundrc ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── __mocks__ └── react.js ├── __tests__ ├── __snapshots__ │ └── hoc_test.js.snap └── hoc_test.js ├── dist ├── react-scrollreveal.cjs.js ├── react-scrollreveal.cjs.js.map ├── react-scrollreveal.esm.js ├── react-scrollreveal.esm.js.map ├── react-scrollreveal.umd.js └── react-scrollreveal.umd.js.map ├── docs ├── index.js └── main.css ├── package-lock.json ├── package.json ├── src └── index.js └── webpack.config.babel.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react" 4 | ], 5 | "plugins": [ 6 | "transform-class-properties", 7 | [ 8 | "transform-react-remove-prop-types", 9 | { 10 | "mode": "wrap" 11 | } 12 | ] 13 | ], 14 | "env": { 15 | "dev": { 16 | "presets": [ 17 | "es2015", 18 | "react-hmre" 19 | ], 20 | "plugins": [ 21 | "transform-class-properties" 22 | ] 23 | }, 24 | "development": { 25 | "presets": [ 26 | "es2015" 27 | ], 28 | "plugins": [ 29 | "transform-class-properties" 30 | ] 31 | }, 32 | "dist": { 33 | "presets": [ 34 | "es2015" 35 | ], 36 | "plugins": [ 37 | "transform-class-properties" 38 | ] 39 | }, 40 | "distMin": { 41 | "presets": [ 42 | "es2015" 43 | ], 44 | "plugins": [ 45 | "transform-class-properties" 46 | ] 47 | }, 48 | "ghPages": { 49 | "presets": [ 50 | "es2015" 51 | ], 52 | "plugins": [ 53 | "transform-class-properties" 54 | ] 55 | }, 56 | "modules": { 57 | "presets": [ 58 | "es2015" 59 | ], 60 | "plugins": [ 61 | "transform-class-properties" 62 | ] 63 | }, 64 | "es6": { 65 | "presets": [ 66 | [ 67 | "es2015", 68 | { 69 | "modules": false 70 | } 71 | ] 72 | ], 73 | "plugins": [ 74 | "transform-class-properties" 75 | ] 76 | }, 77 | "test": { 78 | "presets": [ 79 | "es2015" 80 | ], 81 | "plugins": [ 82 | "transform-class-properties" 83 | ] 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /.bithoundrc: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "dist/*.js" 4 | ] 5 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true, 6 | "jasmine": true, 7 | "node": true 8 | }, 9 | "plugins": [ 10 | "react" 11 | ], 12 | "rules": { 13 | "comma-dangle": ["error", "never"], 14 | "global-require": 0, 15 | "prefer-arrow-callback": 0, 16 | "func-names": 0, 17 | "import/no-extraneous-dependencies": 0, 18 | "no-underscore-dangle": 0, 19 | "no-unused-expressions": 0, 20 | "no-use-before-define": 0, 21 | "react/jsx-filename-extension": 0, 22 | "react/sort-comp": 0, 23 | "react/no-multi-comp": 0, 24 | "react/require-extension": 0 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | bin/* eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #dist/ 2 | *.log 3 | .eslintcache 4 | .idea/ 5 | build/ 6 | coverage/ 7 | dist-es6/ 8 | dist-modules/ 9 | dist/ 10 | gh-pages/ 11 | node_modules/ 12 | node_modules/ 13 | npm-debug.log 14 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | demo/ 2 | dist/ 3 | tests/ 4 | src/ 5 | .* 6 | 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "5" 5 | - "6" 6 | script: 7 | - npm run test:lint 8 | - npm run test:coverage 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REACT-SCROLLREVEAL 2 | React high order component that provides [scrollreveal](https://github.com/jlmakes/scrollreveal) functionality 3 | 4 | ## Usage 5 | - Install `npm i --save react-scrollreveal` 6 | - Wrap component with HOC 7 | ```javascript 8 | import React from 'react' 9 | import withScrollReveal from 'react-scrollreveal' 10 | 11 | class MyComponent extends React.Component { 12 | render() { 13 | const { animationContainerReference } = this.props; 14 | 15 | return ( 16 |
17 | ... 18 |
19 | ) 20 | } 21 | } 22 | 23 | export default withScrollReveal([ 24 | { 25 | selector: '.sr-item', 26 | options: { 27 | reset: true, 28 | }, 29 | }, 30 | { 31 | selector: '.sr-item--sequence', 32 | options: { 33 | reset: true, 34 | delay: 400, 35 | }, 36 | interval: 100 37 | } 38 | ])(MyComponent) 39 | ``` 40 | - ??? 41 | - PROFIT 42 | 43 | ## Reference 44 | withScrollReveal HOC arguments. 45 | You have to provide object or array of objects with shape that described bellow: 46 | 47 | { 48 | selector {string} - css selector to get DOM nodes that init scrollreveal on 49 | options {object} - [scrollreveal configuration](https://github.com/jlmakes/scrollreveal#2-configuration) 50 | interval {number} - interval in milliseconds to create [animation sequence](https://github.com/jlmakes/scrollreveal#3-advanced) for selected elements 51 | } 52 | 53 | 54 | Wrapped component props: 55 | - animationContainerReference {function} - you have to set reference of your animated elements' container 56 | - destroyRevealAnimation {function} - remove all styles, event listeners 57 | - refreshRevealAnimation {function} - reset all styles for all sr elements 58 | -------------------------------------------------------------------------------- /__mocks__/react.js: -------------------------------------------------------------------------------- 1 | const react = require('react'); 2 | // Resolution for requestAnimationFrame not supported in jest error : 3 | // https://github.com/facebook/react/issues/9102#issuecomment-283873039 4 | global.window = global; 5 | window.addEventListener = () => {}; 6 | window.requestAnimationFrame = () => { 7 | throw new Error('requestAnimationFrame is not supported in Node'); 8 | }; 9 | 10 | module.exports = react; 11 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/hoc_test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`HOC should return wrapped React component with additional props 1`] = ` 4 | 9 | `; 10 | -------------------------------------------------------------------------------- /__tests__/hoc_test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import withScrollReveal from '../src/index' 3 | import { isElement } from 'react-dom/test-utils' 4 | import ShallowRenderer from 'react-test-renderer/shallow' 5 | const renderer = new ShallowRenderer(); 6 | 7 | const MyComponent = () => { 8 | return ( 9 |
10 |

Lorem ipsum dolor sit amet.

11 |

Lorem ipsum dolor sit amet.

12 |

Lorem ipsum dolor sit amet.

13 |
14 | ) 15 | }; 16 | 17 | describe('HOC', function () { 18 | it('should take object or array of objects of defined shape as parameter', function () { 19 | expect(withScrollReveal({ selector: '.item', options: { reset: true }, interval: 300 })).not.toThrow(); 20 | expect(withScrollReveal([ 21 | { selector: '.item', options: { reset: true }, interval: 300 }, 22 | { selector: '.item', options: { reset: true } }, 23 | ])).not.toThrow(); 24 | }); 25 | 26 | it('should return wrapped React component with additional props', function () { 27 | const WrappedComponent = withScrollReveal({ 28 | selector: '.item', 29 | options: { reset: true }, 30 | interval: 300 31 | })(MyComponent); 32 | const component = renderer.render(); 33 | const result = renderer.getRenderOutput(); 34 | 35 | expect(isElement(component)).toBe(true); 36 | expect(component).toMatchSnapshot(); 37 | expect(typeof result.props.animationContainerReference).toBe('function'); 38 | expect(typeof result.props.destroyRevealAnimation).toBe('function'); 39 | expect(typeof result.props.refreshRevealAnimation).toBe('function'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /dist/react-scrollreveal.esm.js: -------------------------------------------------------------------------------- 1 | var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; 2 | 3 | 4 | 5 | 6 | 7 | function createCommonjsModule(fn, module) { 8 | return module = { exports: {} }, fn(module, module.exports), module.exports; 9 | } 10 | 11 | /* 12 | object-assign 13 | (c) Sindre Sorhus 14 | @license MIT 15 | */ 16 | 17 | /* eslint-disable no-unused-vars */ 18 | var getOwnPropertySymbols = Object.getOwnPropertySymbols; 19 | var hasOwnProperty = Object.prototype.hasOwnProperty; 20 | var propIsEnumerable = Object.prototype.propertyIsEnumerable; 21 | 22 | function toObject(val) { 23 | if (val === null || val === undefined) { 24 | throw new TypeError('Object.assign cannot be called with null or undefined'); 25 | } 26 | 27 | return Object(val); 28 | } 29 | 30 | function shouldUseNative() { 31 | try { 32 | if (!Object.assign) { 33 | return false; 34 | } 35 | 36 | // Detect buggy property enumeration order in older V8 versions. 37 | 38 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118 39 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers 40 | test1[5] = 'de'; 41 | if (Object.getOwnPropertyNames(test1)[0] === '5') { 42 | return false; 43 | } 44 | 45 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 46 | var test2 = {}; 47 | for (var i = 0; i < 10; i++) { 48 | test2['_' + String.fromCharCode(i)] = i; 49 | } 50 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) { 51 | return test2[n]; 52 | }); 53 | if (order2.join('') !== '0123456789') { 54 | return false; 55 | } 56 | 57 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056 58 | var test3 = {}; 59 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { 60 | test3[letter] = letter; 61 | }); 62 | if (Object.keys(Object.assign({}, test3)).join('') !== 63 | 'abcdefghijklmnopqrst') { 64 | return false; 65 | } 66 | 67 | return true; 68 | } catch (err) { 69 | // We don't expect any of the above to throw, but better to be safe. 70 | return false; 71 | } 72 | } 73 | 74 | var index$1 = shouldUseNative() ? Object.assign : function (target, source) { 75 | var from; 76 | var to = toObject(target); 77 | var symbols; 78 | 79 | for (var s = 1; s < arguments.length; s++) { 80 | from = Object(arguments[s]); 81 | 82 | for (var key in from) { 83 | if (hasOwnProperty.call(from, key)) { 84 | to[key] = from[key]; 85 | } 86 | } 87 | 88 | if (getOwnPropertySymbols) { 89 | symbols = getOwnPropertySymbols(from); 90 | for (var i = 0; i < symbols.length; i++) { 91 | if (propIsEnumerable.call(from, symbols[i])) { 92 | to[symbols[i]] = from[symbols[i]]; 93 | } 94 | } 95 | } 96 | } 97 | 98 | return to; 99 | }; 100 | 101 | /** 102 | * Copyright (c) 2013-present, Facebook, Inc. 103 | * All rights reserved. 104 | * 105 | * This source code is licensed under the BSD-style license found in the 106 | * LICENSE file in the root directory of this source tree. An additional grant 107 | * of patent rights can be found in the PATENTS file in the same directory. 108 | * 109 | */ 110 | 111 | var emptyObject = {}; 112 | 113 | if (process.env.NODE_ENV !== 'production') { 114 | Object.freeze(emptyObject); 115 | } 116 | 117 | var emptyObject_1 = emptyObject; 118 | 119 | /** 120 | * Copyright (c) 2013-present, Facebook, Inc. 121 | * All rights reserved. 122 | * 123 | * This source code is licensed under the BSD-style license found in the 124 | * LICENSE file in the root directory of this source tree. An additional grant 125 | * of patent rights can be found in the PATENTS file in the same directory. 126 | * 127 | */ 128 | 129 | /** 130 | * Use invariant() to assert state which your program assumes to be true. 131 | * 132 | * Provide sprintf-style format (only %s is supported) and arguments 133 | * to provide information about what broke and what you were 134 | * expecting. 135 | * 136 | * The invariant message will be stripped in production, but the invariant 137 | * will remain to ensure logic does not differ in production. 138 | */ 139 | 140 | var validateFormat = function validateFormat(format) {}; 141 | 142 | if (process.env.NODE_ENV !== 'production') { 143 | validateFormat = function validateFormat(format) { 144 | if (format === undefined) { 145 | throw new Error('invariant requires an error message argument'); 146 | } 147 | }; 148 | } 149 | 150 | function invariant(condition, format, a, b, c, d, e, f) { 151 | validateFormat(format); 152 | 153 | if (!condition) { 154 | var error; 155 | if (format === undefined) { 156 | error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); 157 | } else { 158 | var args = [a, b, c, d, e, f]; 159 | var argIndex = 0; 160 | error = new Error(format.replace(/%s/g, function () { 161 | return args[argIndex++]; 162 | })); 163 | error.name = 'Invariant Violation'; 164 | } 165 | 166 | error.framesToPop = 1; // we don't care about invariant's own frame 167 | throw error; 168 | } 169 | } 170 | 171 | var invariant_1 = invariant; 172 | 173 | /** 174 | * Copyright (c) 2013-present, Facebook, Inc. 175 | * All rights reserved. 176 | * 177 | * This source code is licensed under the BSD-style license found in the 178 | * LICENSE file in the root directory of this source tree. An additional grant 179 | * of patent rights can be found in the PATENTS file in the same directory. 180 | * 181 | * 182 | */ 183 | 184 | function makeEmptyFunction(arg) { 185 | return function () { 186 | return arg; 187 | }; 188 | } 189 | 190 | /** 191 | * This function accepts and discards inputs; it has no side effects. This is 192 | * primarily useful idiomatically for overridable function endpoints which 193 | * always need to be callable, since JS lacks a null-call idiom ala Cocoa. 194 | */ 195 | var emptyFunction = function emptyFunction() {}; 196 | 197 | emptyFunction.thatReturns = makeEmptyFunction; 198 | emptyFunction.thatReturnsFalse = makeEmptyFunction(false); 199 | emptyFunction.thatReturnsTrue = makeEmptyFunction(true); 200 | emptyFunction.thatReturnsNull = makeEmptyFunction(null); 201 | emptyFunction.thatReturnsThis = function () { 202 | return this; 203 | }; 204 | emptyFunction.thatReturnsArgument = function (arg) { 205 | return arg; 206 | }; 207 | 208 | var emptyFunction_1 = emptyFunction; 209 | 210 | function e(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r1){for(var s=Array(p),y=0;y1){for(var d=Array(y),m=0;m 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 224 | args[_key - 1] = arguments[_key]; 225 | } 226 | 227 | var argIndex = 0; 228 | var message = 'Warning: ' + format.replace(/%s/g, function () { 229 | return args[argIndex++]; 230 | }); 231 | if (typeof console !== 'undefined') { 232 | console.error(message); 233 | } 234 | try { 235 | // --- Welcome to debugging React --- 236 | // This error was thrown as a convenience so that you can use this stack 237 | // to find the callsite that caused this warning to fire. 238 | throw new Error(message); 239 | } catch (x) {} 240 | }; 241 | 242 | warning = function warning(condition, format) { 243 | if (format === undefined) { 244 | throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); 245 | } 246 | 247 | if (format.indexOf('Failed Composite propType: ') === 0) { 248 | return; // Ignore CompositeComponent proptype check. 249 | } 250 | 251 | if (!condition) { 252 | for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 253 | args[_key2 - 2] = arguments[_key2]; 254 | } 255 | 256 | printWarning.apply(undefined, [format].concat(args)); 257 | } 258 | }; 259 | } 260 | 261 | var warning_1 = warning; 262 | 263 | /** 264 | * Copyright 2013-present, Facebook, Inc. 265 | * All rights reserved. 266 | * 267 | * This source code is licensed under the BSD-style license found in the 268 | * LICENSE file in the root directory of this source tree. An additional grant 269 | * of patent rights can be found in the PATENTS file in the same directory. 270 | */ 271 | 272 | var ReactPropTypesSecret$1 = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 273 | 274 | var ReactPropTypesSecret_1 = ReactPropTypesSecret$1; 275 | 276 | if (process.env.NODE_ENV !== 'production') { 277 | var invariant$1 = invariant_1; 278 | var warning$1 = warning_1; 279 | var ReactPropTypesSecret = ReactPropTypesSecret_1; 280 | var loggedTypeFailures = {}; 281 | } 282 | 283 | /** 284 | * Assert that the values match with the type specs. 285 | * Error messages are memorized and will only be shown once. 286 | * 287 | * @param {object} typeSpecs Map of name to a ReactPropType 288 | * @param {object} values Runtime values that need to be type-checked 289 | * @param {string} location e.g. "prop", "context", "child context" 290 | * @param {string} componentName Name of the component for error messages. 291 | * @param {?Function} getStack Returns the component stack. 292 | * @private 293 | */ 294 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 295 | if (process.env.NODE_ENV !== 'production') { 296 | for (var typeSpecName in typeSpecs) { 297 | if (typeSpecs.hasOwnProperty(typeSpecName)) { 298 | var error; 299 | // Prop type validation may throw. In case they do, we don't want to 300 | // fail the render phase where it didn't fail before. So we log it. 301 | // After these have been cleaned up, we'll let them throw. 302 | try { 303 | // This is intentionally an invariant that gets caught. It's the same 304 | // behavior as without this statement except with a better message. 305 | invariant$1(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', componentName || 'React class', location, typeSpecName); 306 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); 307 | } catch (ex) { 308 | error = ex; 309 | } 310 | warning$1(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error); 311 | if (error instanceof Error && !(error.message in loggedTypeFailures)) { 312 | // Only monitor this failure once because there tends to be a lot of the 313 | // same error. 314 | loggedTypeFailures[error.message] = true; 315 | 316 | var stack = getStack ? getStack() : ''; 317 | 318 | warning$1(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : ''); 319 | } 320 | } 321 | } 322 | } 323 | } 324 | 325 | var checkPropTypes_1 = checkPropTypes; 326 | 327 | var react_development = createCommonjsModule(function (module) { 328 | 'use strict'; 329 | 330 | 331 | if (process.env.NODE_ENV !== "production") { 332 | 333 | 'use strict'; 334 | 335 | var objectAssign$1 = require$$0; 336 | var require$$0 = warning_1; 337 | var emptyObject = emptyObject_1; 338 | var invariant = invariant_1; 339 | var emptyFunction = emptyFunction_1; 340 | var checkPropTypes = checkPropTypes_1; 341 | 342 | /** 343 | * Copyright (c) 2013-present, Facebook, Inc. 344 | * All rights reserved. 345 | * 346 | * This source code is licensed under the BSD-style license found in the 347 | * LICENSE file in the root directory of this source tree. An additional grant 348 | * of patent rights can be found in the PATENTS file in the same directory. 349 | * 350 | * @providesModule reactProdInvariant 351 | * 352 | */ 353 | 354 | { 355 | var warning = require$$0; 356 | } 357 | 358 | function warnNoop(publicInstance, callerName) { 359 | { 360 | var constructor = publicInstance.constructor; 361 | warning(false, '%s(...): Can only update a mounted or mounting component. ' + 'This usually means you called %s() on an unmounted component. ' + 'This is a no-op.\n\nPlease check the code for the %s component.', callerName, callerName, constructor && (constructor.displayName || constructor.name) || 'ReactClass'); 362 | } 363 | } 364 | 365 | /** 366 | * This is the abstract API for an update queue. 367 | */ 368 | var ReactNoopUpdateQueue = { 369 | /** 370 | * Checks whether or not this composite component is mounted. 371 | * @param {ReactClass} publicInstance The instance we want to test. 372 | * @return {boolean} True if mounted, false otherwise. 373 | * @protected 374 | * @final 375 | */ 376 | isMounted: function (publicInstance) { 377 | return false; 378 | }, 379 | 380 | /** 381 | * Forces an update. This should only be invoked when it is known with 382 | * certainty that we are **not** in a DOM transaction. 383 | * 384 | * You may want to call this when you know that some deeper aspect of the 385 | * component's state has changed but `setState` was not called. 386 | * 387 | * This will not invoke `shouldComponentUpdate`, but it will invoke 388 | * `componentWillUpdate` and `componentDidUpdate`. 389 | * 390 | * @param {ReactClass} publicInstance The instance that should rerender. 391 | * @param {?function} callback Called after component is updated. 392 | * @param {?string} Name of the calling function in the public API. 393 | * @internal 394 | */ 395 | enqueueForceUpdate: function (publicInstance, callback, callerName) { 396 | warnNoop(publicInstance, 'forceUpdate'); 397 | }, 398 | 399 | /** 400 | * Replaces all of the state. Always use this or `setState` to mutate state. 401 | * You should treat `this.state` as immutable. 402 | * 403 | * There is no guarantee that `this.state` will be immediately updated, so 404 | * accessing `this.state` after calling this method may return the old value. 405 | * 406 | * @param {ReactClass} publicInstance The instance that should rerender. 407 | * @param {object} completeState Next state. 408 | * @param {?function} callback Called after component is updated. 409 | * @param {?string} Name of the calling function in the public API. 410 | * @internal 411 | */ 412 | enqueueReplaceState: function (publicInstance, completeState, callback, callerName) { 413 | warnNoop(publicInstance, 'replaceState'); 414 | }, 415 | 416 | /** 417 | * Sets a subset of the state. This only exists because _pendingState is 418 | * internal. This provides a merging strategy that is not available to deep 419 | * properties which is confusing. TODO: Expose pendingState or don't use it 420 | * during the merge. 421 | * 422 | * @param {ReactClass} publicInstance The instance that should rerender. 423 | * @param {object} partialState Next partial state to be merged with state. 424 | * @param {?function} callback Called after component is updated. 425 | * @param {?string} Name of the calling function in the public API. 426 | * @internal 427 | */ 428 | enqueueSetState: function (publicInstance, partialState, callback, callerName) { 429 | warnNoop(publicInstance, 'setState'); 430 | } 431 | }; 432 | 433 | var ReactNoopUpdateQueue_1 = ReactNoopUpdateQueue; 434 | 435 | /** 436 | * Copyright 2014-2015, Facebook, Inc. 437 | * All rights reserved. 438 | * 439 | * This source code is licensed under the BSD-style license found in the 440 | * LICENSE file in the root directory of this source tree. An additional grant 441 | * of patent rights can be found in the PATENTS file in the same directory. 442 | * 443 | * @providesModule lowPriorityWarning 444 | */ 445 | 446 | /** 447 | * Forked from fbjs/warning: 448 | * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js 449 | * 450 | * Only change is we use console.warn instead of console.error, 451 | * and do nothing when 'console' is not supported. 452 | * This really simplifies the code. 453 | * --- 454 | * Similar to invariant but only logs a warning if the condition is not met. 455 | * This can be used to log issues in development environments in critical 456 | * paths. Removing the logging code for production environments will keep the 457 | * same logic and follow the same code paths. 458 | */ 459 | 460 | var lowPriorityWarning = function () {}; 461 | 462 | { 463 | var printWarning = function (format) { 464 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 465 | args[_key - 1] = arguments[_key]; 466 | } 467 | 468 | var argIndex = 0; 469 | var message = 'Warning: ' + format.replace(/%s/g, function () { 470 | return args[argIndex++]; 471 | }); 472 | if (typeof console !== 'undefined') { 473 | console.warn(message); 474 | } 475 | try { 476 | // --- Welcome to debugging React --- 477 | // This error was thrown as a convenience so that you can use this stack 478 | // to find the callsite that caused this warning to fire. 479 | throw new Error(message); 480 | } catch (x) {} 481 | }; 482 | 483 | lowPriorityWarning = function (condition, format) { 484 | if (format === undefined) { 485 | throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); 486 | } 487 | if (!condition) { 488 | for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 489 | args[_key2 - 2] = arguments[_key2]; 490 | } 491 | 492 | printWarning.apply(undefined, [format].concat(args)); 493 | } 494 | }; 495 | } 496 | 497 | var lowPriorityWarning_1 = lowPriorityWarning; 498 | 499 | /** 500 | * Base class helpers for the updating state of a component. 501 | */ 502 | function ReactComponent(props, context, updater) { 503 | this.props = props; 504 | this.context = context; 505 | this.refs = emptyObject; 506 | // We initialize the default updater but the real one gets injected by the 507 | // renderer. 508 | this.updater = updater || ReactNoopUpdateQueue_1; 509 | } 510 | 511 | ReactComponent.prototype.isReactComponent = {}; 512 | 513 | /** 514 | * Sets a subset of the state. Always use this to mutate 515 | * state. You should treat `this.state` as immutable. 516 | * 517 | * There is no guarantee that `this.state` will be immediately updated, so 518 | * accessing `this.state` after calling this method may return the old value. 519 | * 520 | * There is no guarantee that calls to `setState` will run synchronously, 521 | * as they may eventually be batched together. You can provide an optional 522 | * callback that will be executed when the call to setState is actually 523 | * completed. 524 | * 525 | * When a function is provided to setState, it will be called at some point in 526 | * the future (not synchronously). It will be called with the up to date 527 | * component arguments (state, props, context). These values can be different 528 | * from this.* because your function may be called after receiveProps but before 529 | * shouldComponentUpdate, and this new state, props, and context will not yet be 530 | * assigned to this. 531 | * 532 | * @param {object|function} partialState Next partial state or function to 533 | * produce next partial state to be merged with current state. 534 | * @param {?function} callback Called after state is updated. 535 | * @final 536 | * @protected 537 | */ 538 | ReactComponent.prototype.setState = function (partialState, callback) { 539 | !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0; 540 | this.updater.enqueueSetState(this, partialState, callback, 'setState'); 541 | }; 542 | 543 | /** 544 | * Forces an update. This should only be invoked when it is known with 545 | * certainty that we are **not** in a DOM transaction. 546 | * 547 | * You may want to call this when you know that some deeper aspect of the 548 | * component's state has changed but `setState` was not called. 549 | * 550 | * This will not invoke `shouldComponentUpdate`, but it will invoke 551 | * `componentWillUpdate` and `componentDidUpdate`. 552 | * 553 | * @param {?function} callback Called after update is complete. 554 | * @final 555 | * @protected 556 | */ 557 | ReactComponent.prototype.forceUpdate = function (callback) { 558 | this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); 559 | }; 560 | 561 | /** 562 | * Deprecated APIs. These APIs used to exist on classic React classes but since 563 | * we would like to deprecate them, we're not going to move them over to this 564 | * modern base class. Instead, we define a getter that warns if it's accessed. 565 | */ 566 | { 567 | var deprecatedAPIs = { 568 | isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'], 569 | replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'] 570 | }; 571 | var defineDeprecationWarning = function (methodName, info) { 572 | Object.defineProperty(ReactComponent.prototype, methodName, { 573 | get: function () { 574 | lowPriorityWarning_1(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]); 575 | return undefined; 576 | } 577 | }); 578 | }; 579 | for (var fnName in deprecatedAPIs) { 580 | if (deprecatedAPIs.hasOwnProperty(fnName)) { 581 | defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); 582 | } 583 | } 584 | } 585 | 586 | /** 587 | * Base class helpers for the updating state of a component. 588 | */ 589 | function ReactPureComponent(props, context, updater) { 590 | // Duplicated from ReactComponent. 591 | this.props = props; 592 | this.context = context; 593 | this.refs = emptyObject; 594 | // We initialize the default updater but the real one gets injected by the 595 | // renderer. 596 | this.updater = updater || ReactNoopUpdateQueue_1; 597 | } 598 | 599 | function ComponentDummy() {} 600 | ComponentDummy.prototype = ReactComponent.prototype; 601 | var pureComponentPrototype = ReactPureComponent.prototype = new ComponentDummy(); 602 | pureComponentPrototype.constructor = ReactPureComponent; 603 | // Avoid an extra prototype jump for these methods. 604 | objectAssign$1(pureComponentPrototype, ReactComponent.prototype); 605 | pureComponentPrototype.isPureReactComponent = true; 606 | 607 | function ReactAsyncComponent(props, context, updater) { 608 | // Duplicated from ReactComponent. 609 | this.props = props; 610 | this.context = context; 611 | this.refs = emptyObject; 612 | // We initialize the default updater but the real one gets injected by the 613 | // renderer. 614 | this.updater = updater || ReactNoopUpdateQueue_1; 615 | } 616 | 617 | var asyncComponentPrototype = ReactAsyncComponent.prototype = new ComponentDummy(); 618 | asyncComponentPrototype.constructor = ReactAsyncComponent; 619 | // Avoid an extra prototype jump for these methods. 620 | objectAssign$1(asyncComponentPrototype, ReactComponent.prototype); 621 | asyncComponentPrototype.unstable_isAsyncReactComponent = true; 622 | asyncComponentPrototype.render = function () { 623 | return this.props.children; 624 | }; 625 | 626 | var ReactBaseClasses = { 627 | Component: ReactComponent, 628 | PureComponent: ReactPureComponent, 629 | AsyncComponent: ReactAsyncComponent 630 | }; 631 | 632 | /** 633 | * Copyright 2013-present, Facebook, Inc. 634 | * All rights reserved. 635 | * 636 | * This source code is licensed under the BSD-style license found in the 637 | * LICENSE file in the root directory of this source tree. An additional grant 638 | * of patent rights can be found in the PATENTS file in the same directory. 639 | * 640 | * @providesModule ReactCurrentOwner 641 | * 642 | */ 643 | 644 | /** 645 | * Keeps track of the current owner. 646 | * 647 | * The current owner is the component who should own any components that are 648 | * currently being constructed. 649 | */ 650 | var ReactCurrentOwner = { 651 | /** 652 | * @internal 653 | * @type {ReactComponent} 654 | */ 655 | current: null 656 | }; 657 | 658 | var ReactCurrentOwner_1 = ReactCurrentOwner; 659 | 660 | var hasOwnProperty = Object.prototype.hasOwnProperty; 661 | 662 | { 663 | var warning$2 = require$$0; 664 | } 665 | 666 | // The Symbol used to tag the ReactElement type. If there is no native Symbol 667 | // nor polyfill, then a plain number is used for performance. 668 | var REACT_ELEMENT_TYPE$1 = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7; 669 | 670 | var RESERVED_PROPS = { 671 | key: true, 672 | ref: true, 673 | __self: true, 674 | __source: true 675 | }; 676 | 677 | var specialPropKeyWarningShown; 678 | var specialPropRefWarningShown; 679 | 680 | function hasValidRef(config) { 681 | { 682 | if (hasOwnProperty.call(config, 'ref')) { 683 | var getter = Object.getOwnPropertyDescriptor(config, 'ref').get; 684 | if (getter && getter.isReactWarning) { 685 | return false; 686 | } 687 | } 688 | } 689 | return config.ref !== undefined; 690 | } 691 | 692 | function hasValidKey(config) { 693 | { 694 | if (hasOwnProperty.call(config, 'key')) { 695 | var getter = Object.getOwnPropertyDescriptor(config, 'key').get; 696 | if (getter && getter.isReactWarning) { 697 | return false; 698 | } 699 | } 700 | } 701 | return config.key !== undefined; 702 | } 703 | 704 | function defineKeyPropWarningGetter(props, displayName) { 705 | var warnAboutAccessingKey = function () { 706 | if (!specialPropKeyWarningShown) { 707 | specialPropKeyWarningShown = true; 708 | warning$2(false, '%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName); 709 | } 710 | }; 711 | warnAboutAccessingKey.isReactWarning = true; 712 | Object.defineProperty(props, 'key', { 713 | get: warnAboutAccessingKey, 714 | configurable: true 715 | }); 716 | } 717 | 718 | function defineRefPropWarningGetter(props, displayName) { 719 | var warnAboutAccessingRef = function () { 720 | if (!specialPropRefWarningShown) { 721 | specialPropRefWarningShown = true; 722 | warning$2(false, '%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://fb.me/react-special-props)', displayName); 723 | } 724 | }; 725 | warnAboutAccessingRef.isReactWarning = true; 726 | Object.defineProperty(props, 'ref', { 727 | get: warnAboutAccessingRef, 728 | configurable: true 729 | }); 730 | } 731 | 732 | /** 733 | * Factory method to create a new React element. This no longer adheres to 734 | * the class pattern, so do not use new to call it. Also, no instanceof check 735 | * will work. Instead test $$typeof field against Symbol.for('react.element') to check 736 | * if something is a React Element. 737 | * 738 | * @param {*} type 739 | * @param {*} key 740 | * @param {string|object} ref 741 | * @param {*} self A *temporary* helper to detect places where `this` is 742 | * different from the `owner` when React.createElement is called, so that we 743 | * can warn. We want to get rid of owner and replace string `ref`s with arrow 744 | * functions, and as long as `this` and owner are the same, there will be no 745 | * change in behavior. 746 | * @param {*} source An annotation object (added by a transpiler or otherwise) 747 | * indicating filename, line number, and/or other information. 748 | * @param {*} owner 749 | * @param {*} props 750 | * @internal 751 | */ 752 | var ReactElement = function (type, key, ref, self, source, owner, props) { 753 | var element = { 754 | // This tag allow us to uniquely identify this as a React Element 755 | $$typeof: REACT_ELEMENT_TYPE$1, 756 | 757 | // Built-in properties that belong on the element 758 | type: type, 759 | key: key, 760 | ref: ref, 761 | props: props, 762 | 763 | // Record the component responsible for creating this element. 764 | _owner: owner 765 | }; 766 | 767 | { 768 | // The validation flag is currently mutative. We put it on 769 | // an external backing store so that we can freeze the whole object. 770 | // This can be replaced with a WeakMap once they are implemented in 771 | // commonly used development environments. 772 | element._store = {}; 773 | 774 | // To make comparing ReactElements easier for testing purposes, we make 775 | // the validation flag non-enumerable (where possible, which should 776 | // include every environment we run tests in), so the test framework 777 | // ignores it. 778 | Object.defineProperty(element._store, 'validated', { 779 | configurable: false, 780 | enumerable: false, 781 | writable: true, 782 | value: false 783 | }); 784 | // self and source are DEV only properties. 785 | Object.defineProperty(element, '_self', { 786 | configurable: false, 787 | enumerable: false, 788 | writable: false, 789 | value: self 790 | }); 791 | // Two elements created in two different places should be considered 792 | // equal for testing purposes and therefore we hide it from enumeration. 793 | Object.defineProperty(element, '_source', { 794 | configurable: false, 795 | enumerable: false, 796 | writable: false, 797 | value: source 798 | }); 799 | if (Object.freeze) { 800 | Object.freeze(element.props); 801 | Object.freeze(element); 802 | } 803 | } 804 | 805 | return element; 806 | }; 807 | 808 | /** 809 | * Create and return a new ReactElement of the given type. 810 | * See https://facebook.github.io/react/docs/react-api.html#createelement 811 | */ 812 | ReactElement.createElement = function (type, config, children) { 813 | var propName; 814 | 815 | // Reserved names are extracted 816 | var props = {}; 817 | 818 | var key = null; 819 | var ref = null; 820 | var self = null; 821 | var source = null; 822 | 823 | if (config != null) { 824 | if (hasValidRef(config)) { 825 | ref = config.ref; 826 | } 827 | if (hasValidKey(config)) { 828 | key = '' + config.key; 829 | } 830 | 831 | self = config.__self === undefined ? null : config.__self; 832 | source = config.__source === undefined ? null : config.__source; 833 | // Remaining properties are added to a new props object 834 | for (propName in config) { 835 | if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { 836 | props[propName] = config[propName]; 837 | } 838 | } 839 | } 840 | 841 | // Children can be more than one argument, and those are transferred onto 842 | // the newly allocated props object. 843 | var childrenLength = arguments.length - 2; 844 | if (childrenLength === 1) { 845 | props.children = children; 846 | } else if (childrenLength > 1) { 847 | var childArray = Array(childrenLength); 848 | for (var i = 0; i < childrenLength; i++) { 849 | childArray[i] = arguments[i + 2]; 850 | } 851 | { 852 | if (Object.freeze) { 853 | Object.freeze(childArray); 854 | } 855 | } 856 | props.children = childArray; 857 | } 858 | 859 | // Resolve default props 860 | if (type && type.defaultProps) { 861 | var defaultProps = type.defaultProps; 862 | for (propName in defaultProps) { 863 | if (props[propName] === undefined) { 864 | props[propName] = defaultProps[propName]; 865 | } 866 | } 867 | } 868 | { 869 | if (key || ref) { 870 | if (typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE$1) { 871 | var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; 872 | if (key) { 873 | defineKeyPropWarningGetter(props, displayName); 874 | } 875 | if (ref) { 876 | defineRefPropWarningGetter(props, displayName); 877 | } 878 | } 879 | } 880 | } 881 | return ReactElement(type, key, ref, self, source, ReactCurrentOwner_1.current, props); 882 | }; 883 | 884 | /** 885 | * Return a function that produces ReactElements of a given type. 886 | * See https://facebook.github.io/react/docs/react-api.html#createfactory 887 | */ 888 | ReactElement.createFactory = function (type) { 889 | var factory = ReactElement.createElement.bind(null, type); 890 | // Expose the type on the factory and the prototype so that it can be 891 | // easily accessed on elements. E.g. `.type === Foo`. 892 | // This should not be named `constructor` since this may not be the function 893 | // that created the element, and it may not even be a constructor. 894 | // Legacy hook TODO: Warn if this is accessed 895 | factory.type = type; 896 | return factory; 897 | }; 898 | 899 | ReactElement.cloneAndReplaceKey = function (oldElement, newKey) { 900 | var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props); 901 | 902 | return newElement; 903 | }; 904 | 905 | /** 906 | * Clone and return a new ReactElement using element as the starting point. 907 | * See https://facebook.github.io/react/docs/react-api.html#cloneelement 908 | */ 909 | ReactElement.cloneElement = function (element, config, children) { 910 | var propName; 911 | 912 | // Original props are copied 913 | var props = objectAssign$1({}, element.props); 914 | 915 | // Reserved names are extracted 916 | var key = element.key; 917 | var ref = element.ref; 918 | // Self is preserved since the owner is preserved. 919 | var self = element._self; 920 | // Source is preserved since cloneElement is unlikely to be targeted by a 921 | // transpiler, and the original source is probably a better indicator of the 922 | // true owner. 923 | var source = element._source; 924 | 925 | // Owner will be preserved, unless ref is overridden 926 | var owner = element._owner; 927 | 928 | if (config != null) { 929 | if (hasValidRef(config)) { 930 | // Silently steal the ref from the parent. 931 | ref = config.ref; 932 | owner = ReactCurrentOwner_1.current; 933 | } 934 | if (hasValidKey(config)) { 935 | key = '' + config.key; 936 | } 937 | 938 | // Remaining properties override existing props 939 | var defaultProps; 940 | if (element.type && element.type.defaultProps) { 941 | defaultProps = element.type.defaultProps; 942 | } 943 | for (propName in config) { 944 | if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { 945 | if (config[propName] === undefined && defaultProps !== undefined) { 946 | // Resolve default props 947 | props[propName] = defaultProps[propName]; 948 | } else { 949 | props[propName] = config[propName]; 950 | } 951 | } 952 | } 953 | } 954 | 955 | // Children can be more than one argument, and those are transferred onto 956 | // the newly allocated props object. 957 | var childrenLength = arguments.length - 2; 958 | if (childrenLength === 1) { 959 | props.children = children; 960 | } else if (childrenLength > 1) { 961 | var childArray = Array(childrenLength); 962 | for (var i = 0; i < childrenLength; i++) { 963 | childArray[i] = arguments[i + 2]; 964 | } 965 | props.children = childArray; 966 | } 967 | 968 | return ReactElement(element.type, key, ref, self, source, owner, props); 969 | }; 970 | 971 | /** 972 | * Verifies the object is a ReactElement. 973 | * See https://facebook.github.io/react/docs/react-api.html#isvalidelement 974 | * @param {?object} object 975 | * @return {boolean} True if `object` is a valid component. 976 | * @final 977 | */ 978 | ReactElement.isValidElement = function (object) { 979 | return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE$1; 980 | }; 981 | 982 | var ReactElement_1 = ReactElement; 983 | 984 | /** 985 | * Copyright 2013-present, Facebook, Inc. 986 | * All rights reserved. 987 | * 988 | * This source code is licensed under the BSD-style license found in the 989 | * LICENSE file in the root directory of this source tree. An additional grant 990 | * of patent rights can be found in the PATENTS file in the same directory. 991 | * 992 | * @providesModule ReactDebugCurrentFrame 993 | * 994 | */ 995 | 996 | var ReactDebugCurrentFrame = {}; 997 | 998 | { 999 | // Component that is being worked on 1000 | ReactDebugCurrentFrame.getCurrentStack = null; 1001 | 1002 | ReactDebugCurrentFrame.getStackAddendum = function () { 1003 | var impl = ReactDebugCurrentFrame.getCurrentStack; 1004 | if (impl) { 1005 | return impl(); 1006 | } 1007 | return null; 1008 | }; 1009 | } 1010 | 1011 | var ReactDebugCurrentFrame_1 = ReactDebugCurrentFrame; 1012 | 1013 | { 1014 | var warning$1 = require$$0; 1015 | 1016 | var _require = ReactDebugCurrentFrame_1, 1017 | getStackAddendum = _require.getStackAddendum; 1018 | } 1019 | 1020 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 1021 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. 1022 | // The Symbol used to tag the ReactElement type. If there is no native Symbol 1023 | // nor polyfill, then a plain number is used for performance. 1024 | var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7; 1025 | 1026 | var SEPARATOR = '.'; 1027 | var SUBSEPARATOR = ':'; 1028 | 1029 | /** 1030 | * Escape and wrap key so it is safe to use as a reactid 1031 | * 1032 | * @param {string} key to be escaped. 1033 | * @return {string} the escaped key. 1034 | */ 1035 | function escape(key) { 1036 | var escapeRegex = /[=:]/g; 1037 | var escaperLookup = { 1038 | '=': '=0', 1039 | ':': '=2' 1040 | }; 1041 | var escapedString = ('' + key).replace(escapeRegex, function (match) { 1042 | return escaperLookup[match]; 1043 | }); 1044 | 1045 | return '$' + escapedString; 1046 | } 1047 | 1048 | /** 1049 | * TODO: Test that a single child and an array with one item have the same key 1050 | * pattern. 1051 | */ 1052 | 1053 | var didWarnAboutMaps = false; 1054 | 1055 | var userProvidedKeyEscapeRegex = /\/+/g; 1056 | function escapeUserProvidedKey(text) { 1057 | return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/'); 1058 | } 1059 | 1060 | var POOL_SIZE = 10; 1061 | var traverseContextPool = []; 1062 | function getPooledTraverseContext(mapResult, keyPrefix, mapFunction, mapContext) { 1063 | if (traverseContextPool.length) { 1064 | var traverseContext = traverseContextPool.pop(); 1065 | traverseContext.result = mapResult; 1066 | traverseContext.keyPrefix = keyPrefix; 1067 | traverseContext.func = mapFunction; 1068 | traverseContext.context = mapContext; 1069 | traverseContext.count = 0; 1070 | return traverseContext; 1071 | } else { 1072 | return { 1073 | result: mapResult, 1074 | keyPrefix: keyPrefix, 1075 | func: mapFunction, 1076 | context: mapContext, 1077 | count: 0 1078 | }; 1079 | } 1080 | } 1081 | 1082 | function releaseTraverseContext(traverseContext) { 1083 | traverseContext.result = null; 1084 | traverseContext.keyPrefix = null; 1085 | traverseContext.func = null; 1086 | traverseContext.context = null; 1087 | traverseContext.count = 0; 1088 | if (traverseContextPool.length < POOL_SIZE) { 1089 | traverseContextPool.push(traverseContext); 1090 | } 1091 | } 1092 | 1093 | /** 1094 | * @param {?*} children Children tree container. 1095 | * @param {!string} nameSoFar Name of the key path so far. 1096 | * @param {!function} callback Callback to invoke with each child found. 1097 | * @param {?*} traverseContext Used to pass information throughout the traversal 1098 | * process. 1099 | * @return {!number} The number of children in this subtree. 1100 | */ 1101 | function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) { 1102 | var type = typeof children; 1103 | 1104 | if (type === 'undefined' || type === 'boolean') { 1105 | // All of the above are perceived as null. 1106 | children = null; 1107 | } 1108 | 1109 | if (children === null || type === 'string' || type === 'number' || 1110 | // The following is inlined from ReactElement. This means we can optimize 1111 | // some checks. React Fiber also inlines this logic for similar purposes. 1112 | type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE) { 1113 | callback(traverseContext, children, 1114 | // If it's the only child, treat the name as if it was wrapped in an array 1115 | // so that it's consistent if the number of children grows. 1116 | nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar); 1117 | return 1; 1118 | } 1119 | 1120 | var child; 1121 | var nextName; 1122 | var subtreeCount = 0; // Count of children found in the current subtree. 1123 | var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR; 1124 | 1125 | if (Array.isArray(children)) { 1126 | for (var i = 0; i < children.length; i++) { 1127 | child = children[i]; 1128 | nextName = nextNamePrefix + getComponentKey(child, i); 1129 | subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext); 1130 | } 1131 | } else { 1132 | var iteratorFn = ITERATOR_SYMBOL && children[ITERATOR_SYMBOL] || children[FAUX_ITERATOR_SYMBOL]; 1133 | if (typeof iteratorFn === 'function') { 1134 | { 1135 | // Warn about using Maps as children 1136 | if (iteratorFn === children.entries) { 1137 | warning$1(didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', getStackAddendum()); 1138 | didWarnAboutMaps = true; 1139 | } 1140 | } 1141 | 1142 | var iterator = iteratorFn.call(children); 1143 | var step; 1144 | var ii = 0; 1145 | while (!(step = iterator.next()).done) { 1146 | child = step.value; 1147 | nextName = nextNamePrefix + getComponentKey(child, ii++); 1148 | subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext); 1149 | } 1150 | } else if (type === 'object') { 1151 | var addendum = ''; 1152 | { 1153 | addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + getStackAddendum(); 1154 | } 1155 | var childrenString = '' + children; 1156 | invariant(false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum); 1157 | } 1158 | } 1159 | 1160 | return subtreeCount; 1161 | } 1162 | 1163 | /** 1164 | * Traverses children that are typically specified as `props.children`, but 1165 | * might also be specified through attributes: 1166 | * 1167 | * - `traverseAllChildren(this.props.children, ...)` 1168 | * - `traverseAllChildren(this.props.leftPanelChildren, ...)` 1169 | * 1170 | * The `traverseContext` is an optional argument that is passed through the 1171 | * entire traversal. It can be used to store accumulations or anything else that 1172 | * the callback might find relevant. 1173 | * 1174 | * @param {?*} children Children tree object. 1175 | * @param {!function} callback To invoke upon traversing each child. 1176 | * @param {?*} traverseContext Context for traversal. 1177 | * @return {!number} The number of children in this subtree. 1178 | */ 1179 | function traverseAllChildren(children, callback, traverseContext) { 1180 | if (children == null) { 1181 | return 0; 1182 | } 1183 | 1184 | return traverseAllChildrenImpl(children, '', callback, traverseContext); 1185 | } 1186 | 1187 | /** 1188 | * Generate a key string that identifies a component within a set. 1189 | * 1190 | * @param {*} component A component that could contain a manual key. 1191 | * @param {number} index Index that is used if a manual key is not provided. 1192 | * @return {string} 1193 | */ 1194 | function getComponentKey(component, index) { 1195 | // Do some typechecking here since we call this blindly. We want to ensure 1196 | // that we don't block potential future ES APIs. 1197 | if (typeof component === 'object' && component !== null && component.key != null) { 1198 | // Explicit key 1199 | return escape(component.key); 1200 | } 1201 | // Implicit key determined by the index in the set 1202 | return index.toString(36); 1203 | } 1204 | 1205 | function forEachSingleChild(bookKeeping, child, name) { 1206 | var func = bookKeeping.func, 1207 | context = bookKeeping.context; 1208 | 1209 | func.call(context, child, bookKeeping.count++); 1210 | } 1211 | 1212 | /** 1213 | * Iterates through children that are typically specified as `props.children`. 1214 | * 1215 | * See https://facebook.github.io/react/docs/react-api.html#react.children.foreach 1216 | * 1217 | * The provided forEachFunc(child, index) will be called for each 1218 | * leaf child. 1219 | * 1220 | * @param {?*} children Children tree container. 1221 | * @param {function(*, int)} forEachFunc 1222 | * @param {*} forEachContext Context for forEachContext. 1223 | */ 1224 | function forEachChildren(children, forEachFunc, forEachContext) { 1225 | if (children == null) { 1226 | return children; 1227 | } 1228 | var traverseContext = getPooledTraverseContext(null, null, forEachFunc, forEachContext); 1229 | traverseAllChildren(children, forEachSingleChild, traverseContext); 1230 | releaseTraverseContext(traverseContext); 1231 | } 1232 | 1233 | function mapSingleChildIntoContext(bookKeeping, child, childKey) { 1234 | var result = bookKeeping.result, 1235 | keyPrefix = bookKeeping.keyPrefix, 1236 | func = bookKeeping.func, 1237 | context = bookKeeping.context; 1238 | 1239 | 1240 | var mappedChild = func.call(context, child, bookKeeping.count++); 1241 | if (Array.isArray(mappedChild)) { 1242 | mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, emptyFunction.thatReturnsArgument); 1243 | } else if (mappedChild != null) { 1244 | if (ReactElement_1.isValidElement(mappedChild)) { 1245 | mappedChild = ReactElement_1.cloneAndReplaceKey(mappedChild, 1246 | // Keep both the (mapped) and old keys if they differ, just as 1247 | // traverseAllChildren used to do for objects as children 1248 | keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey); 1249 | } 1250 | result.push(mappedChild); 1251 | } 1252 | } 1253 | 1254 | function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { 1255 | var escapedPrefix = ''; 1256 | if (prefix != null) { 1257 | escapedPrefix = escapeUserProvidedKey(prefix) + '/'; 1258 | } 1259 | var traverseContext = getPooledTraverseContext(array, escapedPrefix, func, context); 1260 | traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); 1261 | releaseTraverseContext(traverseContext); 1262 | } 1263 | 1264 | /** 1265 | * Maps children that are typically specified as `props.children`. 1266 | * 1267 | * See https://facebook.github.io/react/docs/react-api.html#react.children.map 1268 | * 1269 | * The provided mapFunction(child, key, index) will be called for each 1270 | * leaf child. 1271 | * 1272 | * @param {?*} children Children tree container. 1273 | * @param {function(*, int)} func The map function. 1274 | * @param {*} context Context for mapFunction. 1275 | * @return {object} Object containing the ordered map of results. 1276 | */ 1277 | function mapChildren(children, func, context) { 1278 | if (children == null) { 1279 | return children; 1280 | } 1281 | var result = []; 1282 | mapIntoWithKeyPrefixInternal(children, result, null, func, context); 1283 | return result; 1284 | } 1285 | 1286 | /** 1287 | * Count the number of children that are typically specified as 1288 | * `props.children`. 1289 | * 1290 | * See https://facebook.github.io/react/docs/react-api.html#react.children.count 1291 | * 1292 | * @param {?*} children Children tree container. 1293 | * @return {number} The number of children. 1294 | */ 1295 | function countChildren(children, context) { 1296 | return traverseAllChildren(children, emptyFunction.thatReturnsNull, null); 1297 | } 1298 | 1299 | /** 1300 | * Flatten a children object (typically specified as `props.children`) and 1301 | * return an array with appropriately re-keyed children. 1302 | * 1303 | * See https://facebook.github.io/react/docs/react-api.html#react.children.toarray 1304 | */ 1305 | function toArray(children) { 1306 | var result = []; 1307 | mapIntoWithKeyPrefixInternal(children, result, null, emptyFunction.thatReturnsArgument); 1308 | return result; 1309 | } 1310 | 1311 | var ReactChildren = { 1312 | forEach: forEachChildren, 1313 | map: mapChildren, 1314 | count: countChildren, 1315 | toArray: toArray 1316 | }; 1317 | 1318 | var ReactChildren_1 = ReactChildren; 1319 | 1320 | /** 1321 | * Copyright 2013-present, Facebook, Inc. 1322 | * All rights reserved. 1323 | * 1324 | * This source code is licensed under the BSD-style license found in the 1325 | * LICENSE file in the root directory of this source tree. An additional grant 1326 | * of patent rights can be found in the PATENTS file in the same directory. 1327 | * 1328 | * @providesModule ReactVersion 1329 | */ 1330 | 1331 | var ReactVersion = '16.0.0-beta.2'; 1332 | 1333 | /** 1334 | * Returns the first child in a collection of children and verifies that there 1335 | * is only one child in the collection. 1336 | * 1337 | * See https://facebook.github.io/react/docs/react-api.html#react.children.only 1338 | * 1339 | * The current implementation of this function assumes that a single child gets 1340 | * passed without a wrapper, but the purpose of this helper function is to 1341 | * abstract away the particular structure of children. 1342 | * 1343 | * @param {?object} children Child collection structure. 1344 | * @return {ReactElement} The first and only `ReactElement` contained in the 1345 | * structure. 1346 | */ 1347 | function onlyChild(children) { 1348 | !ReactElement_1.isValidElement(children) ? invariant(false, 'React.Children.only expected to receive a single React element child.') : void 0; 1349 | return children; 1350 | } 1351 | 1352 | var onlyChild_1 = onlyChild; 1353 | 1354 | /** 1355 | * Copyright 2016-present, Facebook, Inc. 1356 | * All rights reserved. 1357 | * 1358 | * This source code is licensed under the BSD-style license found in the 1359 | * LICENSE file in the root directory of this source tree. An additional grant 1360 | * of patent rights can be found in the PATENTS file in the same directory. 1361 | * 1362 | * 1363 | * @providesModule describeComponentFrame 1364 | */ 1365 | 1366 | var describeComponentFrame$1 = function (name, source, ownerName) { 1367 | return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : ''); 1368 | }; 1369 | 1370 | /** 1371 | * Copyright 2013-present, Facebook, Inc. 1372 | * All rights reserved. 1373 | * 1374 | * This source code is licensed under the BSD-style license found in the 1375 | * LICENSE file in the root directory of this source tree. An additional grant 1376 | * of patent rights can be found in the PATENTS file in the same directory. 1377 | * 1378 | * @providesModule getComponentName 1379 | * 1380 | */ 1381 | 1382 | function getComponentName$1(instanceOrFiber) { 1383 | if (typeof instanceOrFiber.getName === 'function') { 1384 | // Stack reconciler 1385 | var instance = instanceOrFiber; 1386 | return instance.getName(); 1387 | } 1388 | if (typeof instanceOrFiber.tag === 'number') { 1389 | // Fiber reconciler 1390 | var fiber = instanceOrFiber; 1391 | var type = fiber.type; 1392 | 1393 | if (typeof type === 'string') { 1394 | return type; 1395 | } 1396 | if (typeof type === 'function') { 1397 | return type.displayName || type.name; 1398 | } 1399 | } 1400 | return null; 1401 | } 1402 | 1403 | var getComponentName_1 = getComponentName$1; 1404 | 1405 | { 1406 | var checkPropTypes$1 = checkPropTypes; 1407 | var lowPriorityWarning$1 = lowPriorityWarning_1; 1408 | var ReactDebugCurrentFrame$1 = ReactDebugCurrentFrame_1; 1409 | var warning$3 = require$$0; 1410 | var describeComponentFrame = describeComponentFrame$1; 1411 | var getComponentName = getComponentName_1; 1412 | 1413 | var currentlyValidatingElement = null; 1414 | 1415 | var getDisplayName = function (element) { 1416 | if (element == null) { 1417 | return '#empty'; 1418 | } else if (typeof element === 'string' || typeof element === 'number') { 1419 | return '#text'; 1420 | } else if (typeof element.type === 'string') { 1421 | return element.type; 1422 | } else { 1423 | return element.type.displayName || element.type.name || 'Unknown'; 1424 | } 1425 | }; 1426 | 1427 | var getStackAddendum$1 = function () { 1428 | var stack = ''; 1429 | if (currentlyValidatingElement) { 1430 | var name = getDisplayName(currentlyValidatingElement); 1431 | var owner = currentlyValidatingElement._owner; 1432 | stack += describeComponentFrame(name, currentlyValidatingElement._source, owner && getComponentName(owner)); 1433 | } 1434 | stack += ReactDebugCurrentFrame$1.getStackAddendum() || ''; 1435 | return stack; 1436 | }; 1437 | } 1438 | 1439 | var ITERATOR_SYMBOL$1 = typeof Symbol === 'function' && Symbol.iterator; 1440 | var FAUX_ITERATOR_SYMBOL$1 = '@@iterator'; // Before Symbol spec. 1441 | 1442 | function getDeclarationErrorAddendum() { 1443 | if (ReactCurrentOwner_1.current) { 1444 | var name = getComponentName(ReactCurrentOwner_1.current); 1445 | if (name) { 1446 | return '\n\nCheck the render method of `' + name + '`.'; 1447 | } 1448 | } 1449 | return ''; 1450 | } 1451 | 1452 | function getSourceInfoErrorAddendum(elementProps) { 1453 | if (elementProps !== null && elementProps !== undefined && elementProps.__source !== undefined) { 1454 | var source = elementProps.__source; 1455 | var fileName = source.fileName.replace(/^.*[\\\/]/, ''); 1456 | var lineNumber = source.lineNumber; 1457 | return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.'; 1458 | } 1459 | return ''; 1460 | } 1461 | 1462 | /** 1463 | * Warn if there's no key explicitly set on dynamic arrays of children or 1464 | * object keys are not valid. This allows us to keep track of children between 1465 | * updates. 1466 | */ 1467 | var ownerHasKeyUseWarning = {}; 1468 | 1469 | function getCurrentComponentErrorInfo(parentType) { 1470 | var info = getDeclarationErrorAddendum(); 1471 | 1472 | if (!info) { 1473 | var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name; 1474 | if (parentName) { 1475 | info = '\n\nCheck the top-level render call using <' + parentName + '>.'; 1476 | } 1477 | } 1478 | return info; 1479 | } 1480 | 1481 | /** 1482 | * Warn if the element doesn't have an explicit key assigned to it. 1483 | * This element is in an array. The array could grow and shrink or be 1484 | * reordered. All children that haven't already been validated are required to 1485 | * have a "key" property assigned to it. Error statuses are cached so a warning 1486 | * will only be shown once. 1487 | * 1488 | * @internal 1489 | * @param {ReactElement} element Element that requires a key. 1490 | * @param {*} parentType element's parent's type. 1491 | */ 1492 | function validateExplicitKey(element, parentType) { 1493 | if (!element._store || element._store.validated || element.key != null) { 1494 | return; 1495 | } 1496 | element._store.validated = true; 1497 | 1498 | var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); 1499 | if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { 1500 | return; 1501 | } 1502 | ownerHasKeyUseWarning[currentComponentErrorInfo] = true; 1503 | 1504 | // Usually the current owner is the offender, but if it accepts children as a 1505 | // property, it may be the creator of the child that's responsible for 1506 | // assigning it a key. 1507 | var childOwner = ''; 1508 | if (element && element._owner && element._owner !== ReactCurrentOwner_1.current) { 1509 | // Give the component that originally created this child. 1510 | childOwner = ' It was passed a child from ' + getComponentName(element._owner) + '.'; 1511 | } 1512 | 1513 | currentlyValidatingElement = element; 1514 | warning$3(false, 'Each child in an array or iterator should have a unique "key" prop.' + '%s%s See https://fb.me/react-warning-keys for more information.%s', currentComponentErrorInfo, childOwner, getStackAddendum$1()); 1515 | currentlyValidatingElement = null; 1516 | } 1517 | 1518 | /** 1519 | * Ensure that every element either is passed in a static location, in an 1520 | * array with an explicit keys property defined, or in an object literal 1521 | * with valid key property. 1522 | * 1523 | * @internal 1524 | * @param {ReactNode} node Statically passed child of any type. 1525 | * @param {*} parentType node's parent's type. 1526 | */ 1527 | function validateChildKeys(node, parentType) { 1528 | if (typeof node !== 'object') { 1529 | return; 1530 | } 1531 | if (Array.isArray(node)) { 1532 | for (var i = 0; i < node.length; i++) { 1533 | var child = node[i]; 1534 | if (ReactElement_1.isValidElement(child)) { 1535 | validateExplicitKey(child, parentType); 1536 | } 1537 | } 1538 | } else if (ReactElement_1.isValidElement(node)) { 1539 | // This element was passed in a valid location. 1540 | if (node._store) { 1541 | node._store.validated = true; 1542 | } 1543 | } else if (node) { 1544 | var iteratorFn = ITERATOR_SYMBOL$1 && node[ITERATOR_SYMBOL$1] || node[FAUX_ITERATOR_SYMBOL$1]; 1545 | if (typeof iteratorFn === 'function') { 1546 | // Entry iterators used to provide implicit keys, 1547 | // but now we print a separate warning for them later. 1548 | if (iteratorFn !== node.entries) { 1549 | var iterator = iteratorFn.call(node); 1550 | var step; 1551 | while (!(step = iterator.next()).done) { 1552 | if (ReactElement_1.isValidElement(step.value)) { 1553 | validateExplicitKey(step.value, parentType); 1554 | } 1555 | } 1556 | } 1557 | } 1558 | } 1559 | } 1560 | 1561 | /** 1562 | * Given an element, validate that its props follow the propTypes definition, 1563 | * provided by the type. 1564 | * 1565 | * @param {ReactElement} element 1566 | */ 1567 | function validatePropTypes(element) { 1568 | var componentClass = element.type; 1569 | if (typeof componentClass !== 'function') { 1570 | return; 1571 | } 1572 | var name = componentClass.displayName || componentClass.name; 1573 | 1574 | // ReactNative `View.propTypes` have been deprecated in favor of `ViewPropTypes`. 1575 | // In their place a temporary getter has been added with a deprecated warning message. 1576 | // Avoid triggering that warning during validation using the temporary workaround, 1577 | // __propTypesSecretDontUseThesePlease. 1578 | // TODO (bvaughn) Revert this particular change any time after April 1 ReactNative tag. 1579 | var propTypes = typeof componentClass.__propTypesSecretDontUseThesePlease === 'object' ? componentClass.__propTypesSecretDontUseThesePlease : componentClass.propTypes; 1580 | 1581 | if (propTypes) { 1582 | currentlyValidatingElement = element; 1583 | checkPropTypes$1(propTypes, element.props, 'prop', name, getStackAddendum$1); 1584 | currentlyValidatingElement = null; 1585 | } 1586 | if (typeof componentClass.getDefaultProps === 'function') { 1587 | warning$3(componentClass.getDefaultProps.isReactClassApproved, 'getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.'); 1588 | } 1589 | } 1590 | 1591 | var ReactElementValidator$1 = { 1592 | createElement: function (type, props, children) { 1593 | var validType = typeof type === 'string' || typeof type === 'function'; 1594 | // We warn in this case but don't throw. We expect the element creation to 1595 | // succeed and there will likely be errors in render. 1596 | if (!validType) { 1597 | var info = ''; 1598 | if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { 1599 | info += ' You likely forgot to export your component from the file ' + "it's defined in."; 1600 | } 1601 | 1602 | var sourceInfo = getSourceInfoErrorAddendum(props); 1603 | if (sourceInfo) { 1604 | info += sourceInfo; 1605 | } else { 1606 | info += getDeclarationErrorAddendum(); 1607 | } 1608 | 1609 | info += ReactDebugCurrentFrame$1.getStackAddendum() || ''; 1610 | 1611 | warning$3(false, 'React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', type == null ? type : typeof type, info); 1612 | } 1613 | 1614 | var element = ReactElement_1.createElement.apply(this, arguments); 1615 | 1616 | // The result can be nullish if a mock or a custom function is used. 1617 | // TODO: Drop this when these are no longer allowed as the type argument. 1618 | if (element == null) { 1619 | return element; 1620 | } 1621 | 1622 | // Skip key warning if the type isn't valid since our key validation logic 1623 | // doesn't expect a non-string/function type and can throw confusing errors. 1624 | // We don't want exception behavior to differ between dev and prod. 1625 | // (Rendering will throw with a helpful message and as soon as the type is 1626 | // fixed, the key warnings will appear.) 1627 | if (validType) { 1628 | for (var i = 2; i < arguments.length; i++) { 1629 | validateChildKeys(arguments[i], type); 1630 | } 1631 | } 1632 | 1633 | validatePropTypes(element); 1634 | 1635 | return element; 1636 | }, 1637 | 1638 | createFactory: function (type) { 1639 | var validatedFactory = ReactElementValidator$1.createElement.bind(null, type); 1640 | // Legacy hook TODO: Warn if this is accessed 1641 | validatedFactory.type = type; 1642 | 1643 | { 1644 | Object.defineProperty(validatedFactory, 'type', { 1645 | enumerable: false, 1646 | get: function () { 1647 | lowPriorityWarning$1(false, 'Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.'); 1648 | Object.defineProperty(this, 'type', { 1649 | value: type 1650 | }); 1651 | return type; 1652 | } 1653 | }); 1654 | } 1655 | 1656 | return validatedFactory; 1657 | }, 1658 | 1659 | cloneElement: function (element, props, children) { 1660 | var newElement = ReactElement_1.cloneElement.apply(this, arguments); 1661 | for (var i = 2; i < arguments.length; i++) { 1662 | validateChildKeys(arguments[i], newElement.type); 1663 | } 1664 | validatePropTypes(newElement); 1665 | return newElement; 1666 | } 1667 | }; 1668 | 1669 | var ReactElementValidator_1 = ReactElementValidator$1; 1670 | 1671 | { 1672 | var warning$4 = require$$0; 1673 | } 1674 | 1675 | function isNative(fn) { 1676 | // Based on isNative() from Lodash 1677 | var funcToString = Function.prototype.toString; 1678 | var reIsNative = RegExp('^' + funcToString 1679 | // Take an example native function source for comparison 1680 | .call(Object.prototype.hasOwnProperty) 1681 | // Strip regex characters so we can use it for regex 1682 | .replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') 1683 | // Remove hasOwnProperty from the template to make it generic 1684 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'); 1685 | try { 1686 | var source = funcToString.call(fn); 1687 | return reIsNative.test(source); 1688 | } catch (err) { 1689 | return false; 1690 | } 1691 | } 1692 | 1693 | var canUseCollections = 1694 | // Array.from 1695 | typeof Array.from === 'function' && 1696 | // Map 1697 | typeof Map === 'function' && isNative(Map) && 1698 | // Map.prototype.keys 1699 | Map.prototype != null && typeof Map.prototype.keys === 'function' && isNative(Map.prototype.keys) && 1700 | // Set 1701 | typeof Set === 'function' && isNative(Set) && 1702 | // Set.prototype.keys 1703 | Set.prototype != null && typeof Set.prototype.keys === 'function' && isNative(Set.prototype.keys); 1704 | 1705 | var setItem; 1706 | var getItem; 1707 | var removeItem; 1708 | var getItemIDs; 1709 | var addRoot; 1710 | var removeRoot; 1711 | var getRootIDs; 1712 | 1713 | if (canUseCollections) { 1714 | var itemMap = new Map(); 1715 | var rootIDSet = new Set(); 1716 | 1717 | setItem = function (id, item) { 1718 | itemMap.set(id, item); 1719 | }; 1720 | getItem = function (id) { 1721 | return itemMap.get(id); 1722 | }; 1723 | removeItem = function (id) { 1724 | itemMap['delete'](id); 1725 | }; 1726 | getItemIDs = function () { 1727 | return Array.from(itemMap.keys()); 1728 | }; 1729 | 1730 | addRoot = function (id) { 1731 | rootIDSet.add(id); 1732 | }; 1733 | removeRoot = function (id) { 1734 | rootIDSet['delete'](id); 1735 | }; 1736 | getRootIDs = function () { 1737 | return Array.from(rootIDSet.keys()); 1738 | }; 1739 | } else { 1740 | var itemByKey = {}; 1741 | var rootByKey = {}; 1742 | 1743 | // Use non-numeric keys to prevent V8 performance issues: 1744 | // https://github.com/facebook/react/pull/7232 1745 | var getKeyFromID = function (id) { 1746 | return '.' + id; 1747 | }; 1748 | var getIDFromKey = function (key) { 1749 | return parseInt(key.substr(1), 10); 1750 | }; 1751 | 1752 | setItem = function (id, item) { 1753 | var key = getKeyFromID(id); 1754 | itemByKey[key] = item; 1755 | }; 1756 | getItem = function (id) { 1757 | var key = getKeyFromID(id); 1758 | return itemByKey[key]; 1759 | }; 1760 | removeItem = function (id) { 1761 | var key = getKeyFromID(id); 1762 | delete itemByKey[key]; 1763 | }; 1764 | getItemIDs = function () { 1765 | return Object.keys(itemByKey).map(getIDFromKey); 1766 | }; 1767 | 1768 | addRoot = function (id) { 1769 | var key = getKeyFromID(id); 1770 | rootByKey[key] = true; 1771 | }; 1772 | removeRoot = function (id) { 1773 | var key = getKeyFromID(id); 1774 | delete rootByKey[key]; 1775 | }; 1776 | getRootIDs = function () { 1777 | return Object.keys(rootByKey).map(getIDFromKey); 1778 | }; 1779 | } 1780 | 1781 | var unmountedIDs = []; 1782 | 1783 | function purgeDeep(id) { 1784 | var item = getItem(id); 1785 | if (item) { 1786 | var childIDs = item.childIDs; 1787 | 1788 | removeItem(id); 1789 | childIDs.forEach(purgeDeep); 1790 | } 1791 | } 1792 | 1793 | function getDisplayName$1(element) { 1794 | if (element == null) { 1795 | return '#empty'; 1796 | } else if (typeof element === 'string' || typeof element === 'number') { 1797 | return '#text'; 1798 | } else if (typeof element.type === 'string') { 1799 | return element.type; 1800 | } else { 1801 | return element.type.displayName || element.type.name || 'Unknown'; 1802 | } 1803 | } 1804 | 1805 | function describeID(id) { 1806 | var name = ReactComponentTreeHook.getDisplayName(id); 1807 | var element = ReactComponentTreeHook.getElement(id); 1808 | var ownerID = ReactComponentTreeHook.getOwnerID(id); 1809 | var ownerName = void 0; 1810 | 1811 | if (ownerID) { 1812 | ownerName = ReactComponentTreeHook.getDisplayName(ownerID); 1813 | } 1814 | warning$4(element, 'ReactComponentTreeHook: Missing React element for debugID %s when ' + 'building stack', id); 1815 | return describeComponentFrame$1(name || '', element && element._source, ownerName || ''); 1816 | } 1817 | 1818 | var ReactComponentTreeHook = { 1819 | onSetChildren: function (id, nextChildIDs) { 1820 | var item = getItem(id); 1821 | !item ? invariant(false, 'Item must have been set') : void 0; 1822 | item.childIDs = nextChildIDs; 1823 | 1824 | for (var i = 0; i < nextChildIDs.length; i++) { 1825 | var nextChildID = nextChildIDs[i]; 1826 | var nextChild = getItem(nextChildID); 1827 | !nextChild ? invariant(false, 'Expected hook events to fire for the child before its parent includes it in onSetChildren().') : void 0; 1828 | !(nextChild.childIDs != null || typeof nextChild.element !== 'object' || nextChild.element == null) ? invariant(false, 'Expected onSetChildren() to fire for a container child before its parent includes it in onSetChildren().') : void 0; 1829 | !nextChild.isMounted ? invariant(false, 'Expected onMountComponent() to fire for the child before its parent includes it in onSetChildren().') : void 0; 1830 | if (nextChild.parentID == null) { 1831 | nextChild.parentID = id; 1832 | // TODO: This shouldn't be necessary but mounting a new root during in 1833 | // componentWillMount currently causes not-yet-mounted components to 1834 | // be purged from our tree data so their parent id is missing. 1835 | } 1836 | !(nextChild.parentID === id) ? invariant(false, 'Expected onBeforeMountComponent() parent and onSetChildren() to be consistent (%s has parents %s and %s).', nextChildID, nextChild.parentID, id) : void 0; 1837 | } 1838 | }, 1839 | onBeforeMountComponent: function (id, element, parentID) { 1840 | var item = { 1841 | element: element, 1842 | parentID: parentID, 1843 | text: null, 1844 | childIDs: [], 1845 | isMounted: false, 1846 | updateCount: 0 1847 | }; 1848 | setItem(id, item); 1849 | }, 1850 | onBeforeUpdateComponent: function (id, element) { 1851 | var item = getItem(id); 1852 | if (!item || !item.isMounted) { 1853 | // We may end up here as a result of setState() in componentWillUnmount(). 1854 | // In this case, ignore the element. 1855 | return; 1856 | } 1857 | item.element = element; 1858 | }, 1859 | onMountComponent: function (id) { 1860 | var item = getItem(id); 1861 | !item ? invariant(false, 'Item must have been set') : void 0; 1862 | item.isMounted = true; 1863 | var isRoot = item.parentID === 0; 1864 | if (isRoot) { 1865 | addRoot(id); 1866 | } 1867 | }, 1868 | onUpdateComponent: function (id) { 1869 | var item = getItem(id); 1870 | if (!item || !item.isMounted) { 1871 | // We may end up here as a result of setState() in componentWillUnmount(). 1872 | // In this case, ignore the element. 1873 | return; 1874 | } 1875 | item.updateCount++; 1876 | }, 1877 | onUnmountComponent: function (id) { 1878 | var item = getItem(id); 1879 | if (item) { 1880 | // We need to check if it exists. 1881 | // `item` might not exist if it is inside an error boundary, and a sibling 1882 | // error boundary child threw while mounting. Then this instance never 1883 | // got a chance to mount, but it still gets an unmounting event during 1884 | // the error boundary cleanup. 1885 | item.isMounted = false; 1886 | var isRoot = item.parentID === 0; 1887 | if (isRoot) { 1888 | removeRoot(id); 1889 | } 1890 | } 1891 | unmountedIDs.push(id); 1892 | }, 1893 | purgeUnmountedComponents: function () { 1894 | if (ReactComponentTreeHook._preventPurging) { 1895 | // Should only be used for testing. 1896 | return; 1897 | } 1898 | 1899 | for (var i = 0; i < unmountedIDs.length; i++) { 1900 | var id = unmountedIDs[i]; 1901 | purgeDeep(id); 1902 | } 1903 | unmountedIDs.length = 0; 1904 | }, 1905 | isMounted: function (id) { 1906 | var item = getItem(id); 1907 | return item ? item.isMounted : false; 1908 | }, 1909 | getCurrentStackAddendum: function () { 1910 | var info = ''; 1911 | var currentOwner = ReactCurrentOwner_1.current; 1912 | if (currentOwner) { 1913 | invariant(typeof currentOwner.tag !== 'number', 'Fiber owners should not show up in Stack stack traces.'); 1914 | if (typeof currentOwner._debugID === 'number') { 1915 | info += ReactComponentTreeHook.getStackAddendumByID(currentOwner._debugID); 1916 | } 1917 | } 1918 | return info; 1919 | }, 1920 | getStackAddendumByID: function (id) { 1921 | var info = ''; 1922 | while (id) { 1923 | info += describeID(id); 1924 | id = ReactComponentTreeHook.getParentID(id); 1925 | } 1926 | return info; 1927 | }, 1928 | getChildIDs: function (id) { 1929 | var item = getItem(id); 1930 | return item ? item.childIDs : []; 1931 | }, 1932 | getDisplayName: function (id) { 1933 | var element = ReactComponentTreeHook.getElement(id); 1934 | if (!element) { 1935 | return null; 1936 | } 1937 | return getDisplayName$1(element); 1938 | }, 1939 | getElement: function (id) { 1940 | var item = getItem(id); 1941 | return item ? item.element : null; 1942 | }, 1943 | getOwnerID: function (id) { 1944 | var element = ReactComponentTreeHook.getElement(id); 1945 | if (!element || !element._owner) { 1946 | return null; 1947 | } 1948 | return element._owner._debugID; 1949 | }, 1950 | getParentID: function (id) { 1951 | var item = getItem(id); 1952 | return item ? item.parentID : null; 1953 | }, 1954 | getSource: function (id) { 1955 | var item = getItem(id); 1956 | var element = item ? item.element : null; 1957 | var source = element != null ? element._source : null; 1958 | return source; 1959 | }, 1960 | getText: function (id) { 1961 | var element = ReactComponentTreeHook.getElement(id); 1962 | if (typeof element === 'string') { 1963 | return element; 1964 | } else if (typeof element === 'number') { 1965 | return '' + element; 1966 | } else { 1967 | return null; 1968 | } 1969 | }, 1970 | getUpdateCount: function (id) { 1971 | var item = getItem(id); 1972 | return item ? item.updateCount : 0; 1973 | }, 1974 | 1975 | 1976 | getRootIDs: getRootIDs, 1977 | getRegisteredIDs: getItemIDs 1978 | }; 1979 | 1980 | var ReactComponentTreeHook_1 = ReactComponentTreeHook; 1981 | 1982 | var createElement = ReactElement_1.createElement; 1983 | var createFactory = ReactElement_1.createFactory; 1984 | var cloneElement = ReactElement_1.cloneElement; 1985 | 1986 | { 1987 | var ReactElementValidator = ReactElementValidator_1; 1988 | createElement = ReactElementValidator.createElement; 1989 | createFactory = ReactElementValidator.createFactory; 1990 | cloneElement = ReactElementValidator.cloneElement; 1991 | } 1992 | 1993 | var React = { 1994 | Children: { 1995 | map: ReactChildren_1.map, 1996 | forEach: ReactChildren_1.forEach, 1997 | count: ReactChildren_1.count, 1998 | toArray: ReactChildren_1.toArray, 1999 | only: onlyChild_1 2000 | }, 2001 | 2002 | Component: ReactBaseClasses.Component, 2003 | PureComponent: ReactBaseClasses.PureComponent, 2004 | unstable_AsyncComponent: ReactBaseClasses.AsyncComponent, 2005 | 2006 | createElement: createElement, 2007 | cloneElement: cloneElement, 2008 | isValidElement: ReactElement_1.isValidElement, 2009 | 2010 | createFactory: createFactory, 2011 | 2012 | version: ReactVersion, 2013 | 2014 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { 2015 | ReactCurrentOwner: ReactCurrentOwner_1 2016 | } 2017 | }; 2018 | 2019 | { 2020 | objectAssign$1(React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, { 2021 | // These should not be included in production. 2022 | ReactComponentTreeHook: ReactComponentTreeHook_1, 2023 | ReactDebugCurrentFrame: ReactDebugCurrentFrame_1 2024 | }); 2025 | } 2026 | 2027 | var ReactEntry = React; 2028 | 2029 | module.exports = ReactEntry; 2030 | 2031 | } 2032 | }); 2033 | 2034 | var index = createCommonjsModule(function (module) { 2035 | 'use strict'; 2036 | 2037 | if (process.env.NODE_ENV === 'production') { 2038 | module.exports = react_production_min; 2039 | } else { 2040 | module.exports = react_development; 2041 | } 2042 | }); 2043 | 2044 | var scrollreveal = createCommonjsModule(function (module, exports) { 2045 | (function (global, factory) { 2046 | module.exports = factory(); 2047 | }(commonjsGlobal, (function () { 'use strict'; 2048 | 2049 | var defaults = { 2050 | delay: 0, 2051 | distance: '0', 2052 | duration: 600, 2053 | easing: 'cubic-bezier(0.6, 0.2, 0.1, 1)', 2054 | opacity: 0, 2055 | origin: 'bottom', 2056 | rotate: { 2057 | x: 0, 2058 | y: 0, 2059 | z: 0, 2060 | }, 2061 | scale: 1, 2062 | container: document.documentElement, 2063 | desktop: true, 2064 | mobile: true, 2065 | reset: false, 2066 | useDelay: 'always', 2067 | viewFactor: 0.0, 2068 | viewOffset: { 2069 | top: 0, 2070 | right: 0, 2071 | bottom: 0, 2072 | left: 0, 2073 | }, 2074 | afterReset: function afterReset () {}, 2075 | afterReveal: function afterReveal () {}, 2076 | beforeReset: function beforeReset () {}, 2077 | beforeReveal: function beforeReveal () {}, 2078 | }; 2079 | 2080 | var noop = { 2081 | clean: function clean () {}, 2082 | destroy: function destroy () {}, 2083 | reveal: function reveal () {}, 2084 | sync: function sync () {}, 2085 | get noop () { return true }, 2086 | }; 2087 | 2088 | function deepAssign (target) { 2089 | var sources = [], len = arguments.length - 1; 2090 | while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; 2091 | 2092 | if (isObject(target)) { 2093 | each(sources, function (source) { 2094 | each(source, function (data, key) { 2095 | if (isObject(data)) { 2096 | if (!target[key] || !isObject(target[key])) { 2097 | target[key] = {}; 2098 | } 2099 | deepAssign(target[key], data); 2100 | } else { 2101 | target[key] = data; 2102 | } 2103 | }); 2104 | }); 2105 | return target 2106 | } else { 2107 | throw new TypeError('Expected an object literal.') 2108 | } 2109 | } 2110 | 2111 | 2112 | function isObject (object) { 2113 | return object !== null && typeof object === 'object' 2114 | && (object.constructor === Object || Object.prototype.toString.call(object) === '[object Object]') 2115 | } 2116 | 2117 | 2118 | function each (collection, callback) { 2119 | if (isObject(collection)) { 2120 | var keys = Object.keys(collection); 2121 | for (var i = 0; i < keys.length; i++) { 2122 | callback(collection[ keys[i] ], keys[i], collection); 2123 | } 2124 | } else if (Array.isArray(collection)) { 2125 | for (var i$1 = 0; i$1 < collection.length; i$1++) { 2126 | callback(collection[i$1], i$1, collection); 2127 | } 2128 | } else { 2129 | throw new TypeError('Expected either an array or object literal.') 2130 | } 2131 | } 2132 | 2133 | 2134 | var nextUniqueId = (function () { 2135 | var uid = 0; 2136 | return function () { return uid++; } 2137 | })(); 2138 | 2139 | var getPrefixedStyleProperty = (function () { 2140 | var properties = {}; 2141 | var style = document.documentElement.style; 2142 | 2143 | function getPrefixedStyleProperty (name, source) { 2144 | if ( source === void 0 ) source = style; 2145 | 2146 | if (name && typeof name === 'string') { 2147 | if (properties[name]) { 2148 | return properties[name] 2149 | } 2150 | if (typeof source[name] === 'string') { 2151 | return properties[name] = name 2152 | } 2153 | if (typeof source[("-webkit-" + name)] === 'string') { 2154 | return properties[name] = "-webkit-" + name 2155 | } 2156 | throw new RangeError(("Unable to find \"" + name + "\" style property.")) 2157 | } 2158 | throw new TypeError('Expected a string.') 2159 | } 2160 | 2161 | getPrefixedStyleProperty.clearCache = function () { return properties = {}; }; 2162 | 2163 | return getPrefixedStyleProperty 2164 | })(); 2165 | 2166 | 2167 | function isMobile (agent) { 2168 | if ( agent === void 0 ) agent = navigator.userAgent; 2169 | 2170 | return /Android|iPhone|iPad|iPod/i.test(agent) 2171 | } 2172 | 2173 | 2174 | function isNode (target) { 2175 | return typeof window.Node === 'object' 2176 | ? target instanceof window.Node 2177 | : target !== null 2178 | && typeof target === 'object' 2179 | && typeof target.nodeType === 'number' 2180 | && typeof target.nodeName === 'string' 2181 | } 2182 | 2183 | 2184 | function isNodeList (target) { 2185 | var prototypeToString = Object.prototype.toString.call(target); 2186 | var regex = /^\[object (HTMLCollection|NodeList|Object)\]$/; 2187 | 2188 | return typeof window.NodeList === 'object' 2189 | ? target instanceof window.NodeList 2190 | : typeof target === 'object' 2191 | && typeof target.length === 'number' 2192 | && regex.test(prototypeToString) 2193 | && (target.length === 0 || isNode(target[0])) 2194 | } 2195 | 2196 | 2197 | function transformSupported () { 2198 | var style = document.documentElement.style; 2199 | return 'transform' in style || 'WebkitTransform' in style 2200 | } 2201 | 2202 | 2203 | function transitionSupported () { 2204 | var style = document.documentElement.style; 2205 | return 'transition' in style || 'WebkitTransition' in style 2206 | } 2207 | 2208 | function isElementVisible (element) { 2209 | var container = this.store.containers[element.containerId]; 2210 | var viewFactor = Math.max(0, Math.min(1, element.config.viewFactor)); 2211 | var viewOffset = element.config.viewOffset; 2212 | 2213 | var elementBounds = { 2214 | top: element.geometry.bounds.top + element.geometry.height * viewFactor, 2215 | right: element.geometry.bounds.right - element.geometry.width * viewFactor, 2216 | bottom: element.geometry.bounds.bottom - element.geometry.height * viewFactor, 2217 | left: element.geometry.bounds.left + element.geometry.width * viewFactor, 2218 | }; 2219 | 2220 | var containerBounds = { 2221 | top: container.geometry.bounds.top + container.scroll.top + viewOffset.top, 2222 | right: container.geometry.bounds.right + container.scroll.left - viewOffset.right, 2223 | bottom: container.geometry.bounds.bottom + container.scroll.top - viewOffset.bottom, 2224 | left: container.geometry.bounds.left + container.scroll.left + viewOffset.left, 2225 | }; 2226 | 2227 | return elementBounds.top < containerBounds.bottom 2228 | && elementBounds.right > containerBounds.left 2229 | && elementBounds.bottom > containerBounds.top 2230 | && elementBounds.left < containerBounds.right 2231 | || element.styles.position === 'fixed' 2232 | } 2233 | 2234 | 2235 | function getGeometry (target, isContainer) { 2236 | /** 2237 | * We want to ignore padding and scrollbars for container elements. 2238 | * More information here: https://goo.gl/vOZpbz 2239 | */ 2240 | var height = (isContainer) ? target.node.clientHeight : target.node.offsetHeight; 2241 | var width = (isContainer) ? target.node.clientWidth : target.node.offsetWidth; 2242 | 2243 | var offsetTop = 0; 2244 | var offsetLeft = 0; 2245 | var node = target.node; 2246 | 2247 | do { 2248 | if (!isNaN(node.offsetTop)) { 2249 | offsetTop += node.offsetTop; 2250 | } 2251 | if (!isNaN(node.offsetLeft)) { 2252 | offsetLeft += node.offsetLeft; 2253 | } 2254 | node = node.offsetParent; 2255 | } while (node) 2256 | 2257 | return { 2258 | bounds: { 2259 | top: offsetTop, 2260 | right: offsetLeft + width, 2261 | bottom: offsetTop + height, 2262 | left: offsetLeft, 2263 | }, 2264 | height: height, 2265 | width: width, 2266 | } 2267 | } 2268 | 2269 | 2270 | function getNode (target, container) { 2271 | if ( container === void 0 ) container = document; 2272 | 2273 | var node = null; 2274 | if (typeof target === 'string') { 2275 | try { 2276 | node = container.querySelector(target); 2277 | } catch (e) { 2278 | throw new Error(("\"" + target + "\" is not a valid selector.")) 2279 | } 2280 | if (!node) { 2281 | throw new Error(("The selector \"" + target + "\" matches 0 elements.")) 2282 | } 2283 | } 2284 | return isNode(target) ? target : node 2285 | } 2286 | 2287 | 2288 | function getNodes (target, container) { 2289 | if ( container === void 0 ) container = document; 2290 | 2291 | if (isNode(target)) { 2292 | return [target] 2293 | } 2294 | if (isNodeList(target)) { 2295 | return Array.prototype.slice.call(target) 2296 | } 2297 | var query; 2298 | if (typeof target === 'string') { 2299 | try { 2300 | query = container.querySelectorAll(target); 2301 | } catch (e) { 2302 | throw new Error(("\"" + target + "\" is not a valid selector.")) 2303 | } 2304 | if (query.length === 0) { 2305 | throw new Error(("The selector \"" + target + "\" matches 0 elements.")) 2306 | } 2307 | } 2308 | return Array.prototype.slice.call(query) 2309 | } 2310 | 2311 | 2312 | function getScrolled (container) { 2313 | return (container.node === document.documentElement) 2314 | ? { 2315 | top: window.pageYOffset, 2316 | left: window.pageXOffset, 2317 | } : { 2318 | top: container.node.scrollTop, 2319 | left: container.node.scrollLeft, 2320 | } 2321 | } 2322 | 2323 | 2324 | function logger (message) { 2325 | var details = [], len = arguments.length - 1; 2326 | while ( len-- > 0 ) details[ len ] = arguments[ len + 1 ]; 2327 | 2328 | if (this.debug && console) { 2329 | var report = "ScrollReveal: " + message; 2330 | details.forEach(function (detail) { return report += "\n - " + detail; }); 2331 | console.log(report); // eslint-disable-line no-console 2332 | } 2333 | } 2334 | 2335 | function rinse () { 2336 | var this$1 = this; 2337 | 2338 | 2339 | var elementIds = { 2340 | active: [], 2341 | stale: [], 2342 | }; 2343 | 2344 | var containerIds = { 2345 | active: [], 2346 | stale: [], 2347 | }; 2348 | 2349 | var sequenceIds = { 2350 | active: [], 2351 | stale: [], 2352 | }; 2353 | 2354 | /** 2355 | * Take stock of active element IDs. 2356 | */ 2357 | try { 2358 | each(getNodes('[data-sr-id]'), function (node) { 2359 | var id = parseInt(node.getAttribute('data-sr-id')); 2360 | elementIds.active.push(id); 2361 | }); 2362 | } catch (e) { 2363 | throw e 2364 | } 2365 | /** 2366 | * Destroy stale elements. 2367 | */ 2368 | each(this.store.elements, function (element) { 2369 | if (elementIds.active.indexOf(element.id) === -1) { 2370 | elementIds.stale.push(element.id); 2371 | } 2372 | }); 2373 | 2374 | each(elementIds.stale, function (staleId) { return delete this$1.store.elements[staleId]; }); 2375 | 2376 | /** 2377 | * Take stock of active container and sequence IDs. 2378 | */ 2379 | each(this.store.elements, function (element) { 2380 | if (containerIds.active.indexOf(element.containerId) === -1) { 2381 | containerIds.active.push(element.containerId); 2382 | } 2383 | if (element.hasOwnProperty('sequence')) { 2384 | if (sequenceIds.active.indexOf(element.sequence.id) === -1) { 2385 | sequenceIds.active.push(element.sequence.id); 2386 | } 2387 | } 2388 | }); 2389 | 2390 | /** 2391 | * Destroy stale containers. 2392 | */ 2393 | each(this.store.containers, function (container) { 2394 | if (containerIds.active.indexOf(container.id) === -1) { 2395 | containerIds.stale.push(container.id); 2396 | } 2397 | }); 2398 | 2399 | each(containerIds.stale, function (staleId) { 2400 | this$1.store.containers[staleId].node.removeEventListener('scroll', this$1.delegate); 2401 | this$1.store.containers[staleId].node.removeEventListener('resize', this$1.delegate); 2402 | delete this$1.store.containers[staleId]; 2403 | }); 2404 | 2405 | /** 2406 | * Destroy stale sequences. 2407 | */ 2408 | each(this.store.sequences, function (sequence) { 2409 | if (sequenceIds.active.indexOf(sequence.id) === -1) { 2410 | sequenceIds.stale.push(sequence.id); 2411 | } 2412 | }); 2413 | 2414 | each(sequenceIds.stale, function (staleId) { return delete this$1.store.sequences[staleId]; }); 2415 | } 2416 | 2417 | function clean (target) { 2418 | var this$1 = this; 2419 | 2420 | 2421 | var dirty; 2422 | try { 2423 | each(getNodes(target), function (node) { 2424 | var id = node.getAttribute('data-sr-id'); 2425 | if (id !== null) { 2426 | dirty = true; 2427 | node.setAttribute('style', this$1.store.elements[id].styles.inline); 2428 | node.removeAttribute('data-sr-id'); 2429 | delete this$1.store.elements[id]; 2430 | } 2431 | }); 2432 | } catch (e) { 2433 | return logger.call(this, 'Clean failed.', e.message) 2434 | } 2435 | 2436 | if (dirty) { 2437 | try { 2438 | rinse.call(this); 2439 | } catch (e) { 2440 | return logger.call(this, 'Clean failed.', 'Rinse failed.', e.message) 2441 | } 2442 | } 2443 | } 2444 | 2445 | function destroy () { 2446 | var this$1 = this; 2447 | 2448 | 2449 | /** 2450 | * Remove all generated styles and element ids 2451 | */ 2452 | each(this.store.elements, function (element) { 2453 | element.node.setAttribute('style', element.styles.inline); 2454 | element.node.removeAttribute('data-sr-id'); 2455 | }); 2456 | 2457 | /** 2458 | * Remove all event listeners. 2459 | */ 2460 | each(this.store.containers, function (container) { 2461 | if (container.node === document.documentElement) { 2462 | window.removeEventListener('scroll', this$1.delegate); 2463 | window.removeEventListener('resize', this$1.delegate); 2464 | } else { 2465 | container.node.removeEventListener('scroll', this$1.delegate); 2466 | container.node.removeEventListener('resize', this$1.delegate); 2467 | } 2468 | }); 2469 | 2470 | /** 2471 | * Clear all data from the store 2472 | */ 2473 | this.store = { 2474 | containers: {}, 2475 | elements: {}, 2476 | history: [], 2477 | sequences: {}, 2478 | }; 2479 | } 2480 | 2481 | /* @license Rematrix v0.1.0 2482 | 2483 | Copyright (c) 2017, Fisssion LLC 2484 | 2485 | Permission is hereby granted, free of charge, to any person obtaining a copy 2486 | of this software and associated documentation files (the "Software"), to deal 2487 | in the Software without restriction, including without limitation the rights 2488 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2489 | copies of the Software, and to permit persons to whom the Software is 2490 | furnished to do so, subject to the following conditions: 2491 | 2492 | The above copyright notice and this permission notice shall be included in 2493 | all copies or substantial portions of the Software. 2494 | 2495 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2496 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2497 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2498 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2499 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2500 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2501 | THE SOFTWARE. 2502 | */ 2503 | /** 2504 | * @module Rematrix 2505 | */ 2506 | 2507 | /** 2508 | * Transformation matrices in the browser come in two flavors: 2509 | * 2510 | * - `matrix` using 6 values (short) 2511 | * - `matrix3d` using 16 values (long) 2512 | * 2513 | * This utility follows this [conversion guide](https://goo.gl/EJlUQ1) 2514 | * to expand short form matrices to their equivalent long form. 2515 | * 2516 | * @param {array} source - Accepts both short and long form matrices. 2517 | * @return {array} 2518 | */ 2519 | function format (source) { 2520 | if (source.constructor !== Array) { 2521 | throw new TypeError('Expected array.') 2522 | } 2523 | if (source.length === 16) { 2524 | return source 2525 | } 2526 | if (source.length === 6) { 2527 | var matrix = identity(); 2528 | matrix[0] = source[0]; 2529 | matrix[1] = source[1]; 2530 | matrix[4] = source[2]; 2531 | matrix[5] = source[3]; 2532 | matrix[12] = source[4]; 2533 | matrix[13] = source[5]; 2534 | return matrix 2535 | } 2536 | throw new RangeError('Expected array with either 6 or 16 values.') 2537 | } 2538 | 2539 | 2540 | /** 2541 | * Returns a matrix representing no transformation. The product of any matrix 2542 | * multiplied by the identity matrix will be the original matrix. 2543 | * 2544 | * > **Tip:** Similar to how `5 * 1 === 5`, where `1` is the identity number. 2545 | * 2546 | * @return {array} 2547 | */ 2548 | function identity () { 2549 | var matrix = []; 2550 | for (var i = 0; i < 16; i++) { 2551 | i % 5 == 0 ? matrix.push(1) : matrix.push(0); 2552 | } 2553 | return matrix 2554 | } 2555 | 2556 | 2557 | /** 2558 | * Returns a 4x4 matrix describing the combined transformations 2559 | * of both arguments. 2560 | * 2561 | * > **Note:** Order is very important. For example, rotating 45° 2562 | * along the Z-axis, followed by translating 500 pixels along the 2563 | * Y-axis... is not the same as translating 500 pixels along the 2564 | * Y-axis, followed by rotating 45° along on the Z-axis. 2565 | * 2566 | * @param {array} m - Accepts both short and long form matrices. 2567 | * @param {array} x - Accepts both short and long form matrices. 2568 | * @return {array} 2569 | */ 2570 | function multiply (m, x) { 2571 | var fm = format(m); 2572 | var fx = format(x); 2573 | var product = []; 2574 | 2575 | for (var i = 0; i < 4; i++) { 2576 | var row = [fm[i], fm[i + 4], fm[i + 8], fm[i + 12]]; 2577 | for (var j = 0; j < 4; j++) { 2578 | var k = j * 4; 2579 | var col = [fx[k], fx[k + 1], fx[k + 2], fx[k + 3]]; 2580 | var result = row[0] * col[0] + row[1] * col[1] + row[2] * col[2] + row[3] * col[3]; 2581 | 2582 | product[i + k] = result; 2583 | } 2584 | } 2585 | 2586 | return product 2587 | } 2588 | 2589 | 2590 | /** 2591 | * Attempts to return a 4x4 matrix describing the CSS transform 2592 | * matrix passed in, but will return the identity matrix as a 2593 | * fallback. 2594 | * 2595 | * **Tip:** In virtually all cases, this method is used to convert 2596 | * a CSS matrix (retrieved as a `string` from computed styles) to 2597 | * its equivalent array format. 2598 | * 2599 | * @param {string} source - String containing a valid CSS `matrix` or `matrix3d` property. 2600 | * @return {array} 2601 | */ 2602 | function parse (source) { 2603 | if (typeof source === 'string') { 2604 | var match = source.match(/matrix(3d)?\(([^)]+)\)/); 2605 | if (match) { 2606 | var raw = match[2].split(', ').map(function (value) { return parseFloat(value); }); 2607 | return format(raw) 2608 | } 2609 | } 2610 | return identity() 2611 | } 2612 | 2613 | 2614 | /** 2615 | * Returns a 4x4 matrix describing X-axis rotation. 2616 | * 2617 | * @param {number} angle - Measured in degrees. 2618 | * @return {array} 2619 | */ 2620 | function rotateX (angle) { 2621 | var theta = Math.PI / 180 * angle; 2622 | var matrix = identity(); 2623 | 2624 | matrix[5] = matrix[10] = Math.cos(theta); 2625 | matrix[6] = matrix[9] = Math.sin(theta); 2626 | matrix[9] *= -1; 2627 | 2628 | return matrix 2629 | } 2630 | 2631 | 2632 | /** 2633 | * Returns a 4x4 matrix describing Y-axis rotation. 2634 | * 2635 | * @param {number} angle - Measured in degrees. 2636 | * @return {array} 2637 | */ 2638 | function rotateY (angle) { 2639 | var theta = Math.PI / 180 * angle; 2640 | var matrix = identity(); 2641 | 2642 | matrix[0] = matrix[10] = Math.cos(theta); 2643 | matrix[2] = matrix[8] = Math.sin(theta); 2644 | matrix[2] *= -1; 2645 | 2646 | return matrix 2647 | } 2648 | 2649 | 2650 | /** 2651 | * Returns a 4x4 matrix describing Z-axis rotation. 2652 | * 2653 | * @param {number} angle - Measured in degrees. 2654 | * @return {array} 2655 | */ 2656 | function rotateZ (angle) { 2657 | var theta = Math.PI / 180 * angle; 2658 | var matrix = identity(); 2659 | 2660 | matrix[0] = matrix[5] = Math.cos(theta); 2661 | matrix[1] = matrix[4] = Math.sin(theta); 2662 | matrix[4] *= -1; 2663 | 2664 | return matrix 2665 | } 2666 | 2667 | 2668 | /** 2669 | * Returns a 4x4 matrix describing 2D scaling. The first argument 2670 | * is used for both X and Y-axis scaling, unless an optional 2671 | * second argument is provided to explicitly define Y-axis scaling. 2672 | * 2673 | * @param {number} scalarX - Decimal multiplier. 2674 | * @param {number} [scalarY] - Decimal multiplier. 2675 | * @return {array} 2676 | */ 2677 | function scale (scalarX, scalarY) { 2678 | var matrix = identity(); 2679 | matrix[0] = scalarX; 2680 | matrix[5] = scalarY || scalarX; 2681 | return matrix 2682 | } 2683 | 2684 | 2685 | /** 2686 | * Returns a 4x4 matrix describing X-axis translation. 2687 | * 2688 | * @param {number} distance - Measured in pixels. 2689 | * @return {array} 2690 | */ 2691 | function translateX (distance) { 2692 | var matrix = identity(); 2693 | matrix[12] = distance; 2694 | return matrix 2695 | } 2696 | 2697 | 2698 | /** 2699 | * Returns a 4x4 matrix describing Y-axis translation. 2700 | * 2701 | * @param {number} distance - Measured in pixels. 2702 | * @return {array} 2703 | */ 2704 | function translateY (distance) { 2705 | var matrix = identity(); 2706 | matrix[13] = distance; 2707 | return matrix 2708 | } 2709 | 2710 | function style (element) { 2711 | var computed = window.getComputedStyle(element.node); 2712 | var position = computed.position; 2713 | var config = element.config; 2714 | 2715 | /** 2716 | * Generate inline styles 2717 | */ 2718 | var inlineRegex = /.+[^;]/g; 2719 | var inlineStyle = element.node.getAttribute('style') || ''; 2720 | var inlineMatch = inlineRegex.exec(inlineStyle); 2721 | 2722 | var inline = (inlineMatch) ? ((inlineMatch[0]) + ";") : ''; 2723 | if (inline.indexOf('visibility: visible') === -1) { 2724 | inline += (inline.length) ? ' ' : ''; 2725 | inline += 'visibility: visible;'; 2726 | } 2727 | 2728 | /** 2729 | * Generate opacity styles 2730 | */ 2731 | var computedOpacity = parseFloat(computed.opacity); 2732 | var configOpacity = !isNaN(parseFloat(config.opacity)) 2733 | ? parseFloat(config.opacity) 2734 | : parseFloat(computed.opacity); 2735 | 2736 | var opacity = { 2737 | computed: (computedOpacity !== configOpacity) ? ("opacity: " + computedOpacity + ";") : '', 2738 | generated: (computedOpacity !== configOpacity) ? ("opacity: " + configOpacity + ";") : '', 2739 | }; 2740 | 2741 | /** 2742 | * Generate transformation styles 2743 | */ 2744 | var transformations = []; 2745 | 2746 | if (parseFloat(config.distance)) { 2747 | var axis = (config.origin === 'top' || config.origin === 'bottom') ? 'Y' : 'X'; 2748 | 2749 | /** 2750 | * Let’s make sure our our pixel distances are negative for top and left. 2751 | * e.g. { origin: 'top', distance: '25px' } starts at `top: -25px` in CSS. 2752 | */ 2753 | var distance = config.distance; 2754 | if (config.origin === 'top' || config.origin === 'left') { 2755 | distance = /^-/.test(distance) 2756 | ? distance.substr(1) 2757 | : ("-" + distance); 2758 | } 2759 | 2760 | var ref = distance.match(/(^-?\d+\.?\d?)|(em$|px$|\%$)/g); 2761 | var value = ref[0]; 2762 | var unit = ref[1]; 2763 | 2764 | switch (unit) { 2765 | case 'em': 2766 | distance = parseInt(computed.fontSize) * value; 2767 | break 2768 | case 'px': 2769 | distance = value; 2770 | break 2771 | case '%': 2772 | distance = (axis === 'Y') 2773 | ? element.node.getBoundingClientRect().height * value / 100 2774 | : element.node.getBoundingClientRect().width * value / 100; 2775 | break 2776 | default: 2777 | throw new RangeError('Unrecognized or missing distance unit.') 2778 | } 2779 | 2780 | (axis === 'Y') 2781 | ? transformations.push(translateY(distance)) 2782 | : transformations.push(translateX(distance)); 2783 | } 2784 | 2785 | if (config.rotate.x) { transformations.push(rotateX(config.rotate.x)); } 2786 | if (config.rotate.y) { transformations.push(rotateY(config.rotate.y)); } 2787 | if (config.rotate.z) { transformations.push(rotateZ(config.rotate.z)); } 2788 | if (config.scale !== 1) { 2789 | config.scale === 0 2790 | ? transformations.push(scale(0.0002)) 2791 | : transformations.push(scale(config.scale)); 2792 | } 2793 | 2794 | var transform = {}; 2795 | if (transformations.length) { 2796 | 2797 | transform.property = getPrefixedStyleProperty('transform'); 2798 | /** 2799 | * The default computed transform value should be one of: 2800 | * undefined || 'none' || 'matrix()' || 'matrix3d()' 2801 | */ 2802 | transform.computed = { 2803 | raw: computed[transform.property], 2804 | matrix: parse(computed[transform.property]), 2805 | }; 2806 | 2807 | transformations.unshift(transform.computed.matrix); 2808 | var product = transformations.reduce(multiply); 2809 | 2810 | transform.generated = { 2811 | initial: ((transform.property) + ": matrix3d(" + (product.join(', ')) + ");"), 2812 | final: ((transform.property) + ": matrix3d(" + (transform.computed.matrix.join(', ')) + ");"), 2813 | }; 2814 | } else { 2815 | transform.generated = { 2816 | initial: '', 2817 | final: '', 2818 | }; 2819 | } 2820 | 2821 | /** 2822 | * Generate transition styles 2823 | */ 2824 | var transition = {}; 2825 | if (opacity.generated || transform.generated.initial) { 2826 | 2827 | transition.property = getPrefixedStyleProperty('transition'); 2828 | transition.computed = computed[transition.property]; 2829 | transition.fragments = []; 2830 | 2831 | var delay = config.delay; 2832 | var duration = config.duration; 2833 | var easing = config.easing; 2834 | 2835 | if (opacity.generated) { 2836 | transition.fragments.push({ 2837 | delayed: ("opacity " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), 2838 | instant: ("opacity " + (duration / 1000) + "s " + easing + " 0s"), 2839 | }); 2840 | } 2841 | 2842 | if (transform.generated.initial) { 2843 | transition.fragments.push({ 2844 | delayed: ((transform.property) + " " + (duration / 1000) + "s " + easing + " " + (delay / 1000) + "s"), 2845 | instant: ((transform.property) + " " + (duration / 1000) + "s " + easing + " 0s"), 2846 | }); 2847 | } 2848 | 2849 | /** 2850 | * The default computed transition property should be one of: 2851 | * undefined || '' || 'all 0s ease 0s' || 'all 0s 0s cubic-bezier()' 2852 | */ 2853 | if (transition.computed && !transition.computed.match(/all 0s/)) { 2854 | transition.fragments.unshift({ 2855 | delayed: transition.computed, 2856 | instant: transition.computed, 2857 | }); 2858 | } 2859 | 2860 | var composed = transition.fragments.reduce(function (composition, fragment, i) { 2861 | composition.delayed += (i === 0) ? fragment.delayed : (", " + (fragment.delayed)); 2862 | composition.instant += (i === 0) ? fragment.instant : (", " + (fragment.instant)); 2863 | return composition 2864 | }, { 2865 | delayed: '', 2866 | instant: '', 2867 | }); 2868 | 2869 | transition.generated = { 2870 | delayed: ((transition.property) + ": " + (composed.delayed) + ";"), 2871 | instant: ((transition.property) + ": " + (composed.instant) + ";"), 2872 | }; 2873 | } else { 2874 | transition.generated = { 2875 | delayed: '', 2876 | instant: '', 2877 | }; 2878 | } 2879 | 2880 | return { 2881 | inline: inline, 2882 | opacity: opacity, 2883 | position: position, 2884 | transform: transform, 2885 | transition: transition, 2886 | } 2887 | } 2888 | 2889 | function initialize () { 2890 | var this$1 = this; 2891 | 2892 | 2893 | rinse.call(this); 2894 | 2895 | each(this.store.elements, function (element) { 2896 | var styles = [element.styles.inline]; 2897 | 2898 | if (element.visible) { 2899 | styles.push(element.styles.opacity.computed); 2900 | styles.push(element.styles.transform.generated.final); 2901 | } else { 2902 | styles.push(element.styles.opacity.generated); 2903 | styles.push(element.styles.transform.generated.initial); 2904 | } 2905 | 2906 | element.node.setAttribute('style', styles.filter(function (i) { return i !== ''; }).join(' ')); 2907 | }); 2908 | 2909 | each(this.store.containers, function (container) { 2910 | if (container.node === document.documentElement) { 2911 | window.addEventListener('scroll', this$1.delegate); 2912 | window.addEventListener('resize', this$1.delegate); 2913 | } else { 2914 | container.node.addEventListener('scroll', this$1.delegate); 2915 | container.node.addEventListener('resize', this$1.delegate); 2916 | } 2917 | }); 2918 | 2919 | /** 2920 | * Manually invoke delegate once to capture 2921 | * element and container dimensions, container 2922 | * scroll position, and trigger any valid reveals 2923 | */ 2924 | this.delegate(); 2925 | 2926 | this.initTimeout = null; 2927 | } 2928 | 2929 | function reveal (target, options, interval, sync) { 2930 | var this$1 = this; 2931 | 2932 | 2933 | /** 2934 | * The reveal method has an optional 2nd parameter, 2935 | * so here we just shuffle things around to accept 2936 | * the interval being passed as the 2nd argument. 2937 | */ 2938 | if (typeof options === 'number') { 2939 | interval = Math.abs(parseInt(options)); 2940 | options = {}; 2941 | } else { 2942 | interval = Math.abs(parseInt(interval)); 2943 | options = options || {}; 2944 | } 2945 | 2946 | var config = deepAssign({}, this.defaults, options); 2947 | var containers = this.store.containers; 2948 | 2949 | var container; 2950 | var targets; 2951 | try { 2952 | container = getNode(config.container); 2953 | if (!container) { 2954 | throw new Error('Invalid container.') 2955 | } 2956 | targets = getNodes(target, container); 2957 | if (!targets) { 2958 | throw new Error('Nothing to animate.') 2959 | } 2960 | } catch (e) { 2961 | return logger.call(this, 'Reveal failed.', e.message) 2962 | } 2963 | 2964 | /** 2965 | * Verify our platform matches our platform configuration. 2966 | */ 2967 | if (!config.mobile && isMobile() || !config.desktop && !isMobile()) { 2968 | return logger.call(this, 'Reveal aborted.', 'This platform has been disabled.') 2969 | } 2970 | 2971 | /** 2972 | * Sequence intervals must be at least 16ms (60fps). 2973 | */ 2974 | var sequence; 2975 | if (interval) { 2976 | if (interval >= 16) { 2977 | var sequenceId = nextUniqueId(); 2978 | sequence = { 2979 | elementIds: [], 2980 | nose: { blocked: false, index: null, pointer: null }, 2981 | tail: { blocked: false, index: null, pointer: null }, 2982 | id: sequenceId, 2983 | interval: Math.abs(interval), 2984 | }; 2985 | } else { 2986 | return logger.call(this, 'Reveal failed.', 'Sequence interval must be at least 16ms.') 2987 | } 2988 | } 2989 | 2990 | var containerId; 2991 | each(containers, function (storedContainer) { 2992 | if (!containerId && storedContainer.node === container) { 2993 | containerId = storedContainer.id; 2994 | } 2995 | }); 2996 | 2997 | if (isNaN(containerId)) { 2998 | containerId = nextUniqueId(); 2999 | } 3000 | 3001 | try { 3002 | var elements = targets.map(function (node) { 3003 | var element = {}; 3004 | var existingId = node.getAttribute('data-sr-id'); 3005 | 3006 | if (existingId) { 3007 | deepAssign(element, this$1.store.elements[existingId]); 3008 | 3009 | /** 3010 | * In order to prevent previously generated styles 3011 | * from throwing off the new styles, the style tag 3012 | * has to be reverted to it's pre-reveal state. 3013 | */ 3014 | element.node.setAttribute('style', element.styles.inline); 3015 | 3016 | } else { 3017 | element.id = nextUniqueId(); 3018 | element.node = node; 3019 | element.seen = false; 3020 | element.revealed = false; 3021 | element.visible = false; 3022 | } 3023 | 3024 | element.config = config; 3025 | element.containerId = containerId; 3026 | element.styles = style(element); 3027 | 3028 | if (sequence) { 3029 | element.sequence = { 3030 | id: sequence.id, 3031 | index: sequence.elementIds.length, 3032 | }; 3033 | sequence.elementIds.push(element.id); 3034 | } 3035 | 3036 | return element 3037 | }); 3038 | 3039 | /** 3040 | * Modifying the DOM via setAttribute needs to be handled 3041 | * separately from reading computed styles in the map above 3042 | * for the browser to batch DOM changes (limiting reflows) 3043 | */ 3044 | each(elements, function (element) { 3045 | this$1.store.elements[element.id] = element; 3046 | element.node.setAttribute('data-sr-id', element.id); 3047 | }); 3048 | 3049 | } catch (e) { 3050 | return logger.call(this, 'Reveal failed.', e.message) 3051 | } 3052 | 3053 | containers[containerId] = containers[containerId] || { 3054 | id: containerId, 3055 | node: container, 3056 | }; 3057 | 3058 | if (sequence) { 3059 | this.store.sequences[sequence.id] = sequence; 3060 | } 3061 | 3062 | /** 3063 | * If reveal wasn't invoked by sync, we want to 3064 | * make sure to add this call to the history. 3065 | */ 3066 | if (!sync) { 3067 | this.store.history.push({ target: target, options: options, interval: interval }); 3068 | 3069 | /** 3070 | * Push initialization to the event queue, giving 3071 | * multiple reveal calls time to be interpretted. 3072 | */ 3073 | if (this.initTimeout) { 3074 | window.clearTimeout(this.initTimeout); 3075 | } 3076 | this.initTimeout = window.setTimeout(initialize.bind(this), 0); 3077 | } 3078 | } 3079 | 3080 | /** 3081 | * Re-runs the reveal method for each record stored in history, 3082 | * for capturing new content asynchronously loaded into the DOM. 3083 | */ 3084 | function sync () { 3085 | var this$1 = this; 3086 | 3087 | each(this.store.history, function (record) { 3088 | reveal.call(this$1, record.target, record.options, record.interval, true); 3089 | }); 3090 | 3091 | initialize.call(this); 3092 | } 3093 | 3094 | function animate (element, sequencing) { 3095 | 3096 | var sequence = (element.sequence) ? this.store.sequences[element.sequence.id] : false; 3097 | var delayed = element.config.useDelay === 'always' 3098 | || element.config.useDelay === 'onload' && this.pristine 3099 | || element.config.useDelay === 'once' && !element.seen; 3100 | 3101 | element.visible = isElementVisible.call(this, element); 3102 | 3103 | if (sequencing) { 3104 | if (element.sequence.index === sequence.nose.pointer - 1 && sequence.nose.pointer > sequence.nose.index) { 3105 | sequence.nose.pointer--; 3106 | queueSequenceNose.call(this, sequence); 3107 | } else if (element.sequence.index === sequence.tail.pointer + 1 && sequence.tail.pointer < sequence.tail.index) { 3108 | sequence.tail.pointer++; 3109 | queueSequenceTail.call(this, sequence); 3110 | } else { 3111 | return 3112 | } 3113 | return triggerReveal.call(this, element, delayed) 3114 | } 3115 | 3116 | if (element.visible && !element.revealed) { 3117 | if (sequence) { 3118 | updateSequenceIndexes.call(this, sequence); 3119 | if (sequence.nose.pointer === null && sequence.tail.pointer === null) { 3120 | sequence.nose.pointer = sequence.tail.pointer = element.sequence.index; 3121 | queueSequenceNose.call(this, sequence); 3122 | queueSequenceTail.call(this, sequence); 3123 | } else if (element.sequence.index === sequence.nose.pointer - 1 && !sequence.nose.blocked) { 3124 | sequence.nose.pointer--; 3125 | queueSequenceNose.call(this, sequence); 3126 | } else if (element.sequence.index === sequence.tail.pointer + 1 && !sequence.tail.blocked) { 3127 | sequence.tail.pointer++; 3128 | queueSequenceTail.call(this, sequence); 3129 | } else { 3130 | return 3131 | } 3132 | } 3133 | return triggerReveal.call(this, element, delayed) 3134 | } 3135 | 3136 | if (!element.visible && element.revealed && element.config.reset) { 3137 | if (sequence) { 3138 | updateSequenceIndexes.call(this, sequence); 3139 | if (sequence.nose.index !== Infinity && sequence.tail.index !== -Infinity) { 3140 | sequence.nose.pointer = Math.max(sequence.nose.pointer, sequence.nose.index); 3141 | sequence.tail.pointer = Math.min(sequence.tail.pointer, sequence.tail.index); 3142 | } 3143 | } 3144 | return triggerReset.call(this, element) 3145 | } 3146 | } 3147 | 3148 | 3149 | function triggerReveal (element, delayed) { 3150 | var styles = [ 3151 | element.styles.inline, 3152 | element.styles.opacity.computed, 3153 | element.styles.transform.generated.final ]; 3154 | delayed 3155 | ? styles.push(element.styles.transition.generated.delayed) 3156 | : styles.push(element.styles.transition.generated.instant); 3157 | element.revealed = element.seen = true; 3158 | element.node.setAttribute('style', styles.filter(function (i) { return i !== ''; }).join(' ')); 3159 | registerCallbacks.call(this, element, delayed); 3160 | } 3161 | 3162 | 3163 | function triggerReset (element) { 3164 | var styles = [ 3165 | element.styles.inline, 3166 | element.styles.opacity.generated, 3167 | element.styles.transform.generated.initial, 3168 | element.styles.transition.generated.instant ]; 3169 | element.revealed = false; 3170 | element.node.setAttribute('style', styles.filter(function (i) { return i !== ''; }).join(' ')); 3171 | registerCallbacks.call(this, element); 3172 | } 3173 | 3174 | 3175 | function registerCallbacks (element, isDelayed) { 3176 | var this$1 = this; 3177 | 3178 | var duration = isDelayed 3179 | ? element.config.duration + element.config.delay 3180 | : element.config.duration; 3181 | 3182 | var beforeCallback = element.revealed 3183 | ? element.config.beforeReveal 3184 | : element.config.beforeReset; 3185 | 3186 | var afterCallback = element.revealed 3187 | ? element.config.afterReveal 3188 | : element.config.afterReset; 3189 | 3190 | var elapsed = 0; 3191 | if (element.callbackTimer) { 3192 | elapsed = Date.now() - element.callbackTimer.start; 3193 | window.clearTimeout(element.callbackTimer.clock); 3194 | } 3195 | 3196 | beforeCallback(element.node); 3197 | 3198 | element.callbackTimer = { 3199 | start: Date.now(), 3200 | clock: window.setTimeout(function () { 3201 | afterCallback(element.node); 3202 | element.callbackTimer = null; 3203 | if (element.revealed && !element.config.reset) { 3204 | clean.call(this$1, element.node); 3205 | } 3206 | }, duration - elapsed), 3207 | }; 3208 | } 3209 | 3210 | 3211 | function updateSequenceIndexes (sequence) { 3212 | var this$1 = this; 3213 | 3214 | var min = Infinity; 3215 | var max = -Infinity; 3216 | each(sequence.elementIds, function (id) { 3217 | var element = this$1.store.elements[id]; 3218 | if (element && element.visible) { 3219 | min = Math.min(min, element.sequence.index); 3220 | max = Math.max(max, element.sequence.index); 3221 | } 3222 | }); 3223 | sequence.nose.index = min; 3224 | sequence.tail.index = max; 3225 | } 3226 | 3227 | 3228 | function queueSequenceNose (sequence) { 3229 | var this$1 = this; 3230 | 3231 | var nextId = sequence.elementIds[sequence.nose.pointer - 1]; 3232 | var nextElement = this.store.elements[nextId]; 3233 | if (nextElement) { 3234 | sequence.nose.blocked = true; 3235 | window.setTimeout(function () { 3236 | sequence.nose.blocked = false; 3237 | animate.call(this$1, nextElement, true); 3238 | }, sequence.interval); 3239 | } 3240 | } 3241 | 3242 | 3243 | function queueSequenceTail (sequence) { 3244 | var this$1 = this; 3245 | 3246 | var nextId = sequence.elementIds[sequence.tail.pointer + 1]; 3247 | var nextElement = this.store.elements[nextId]; 3248 | if (nextElement) { 3249 | sequence.tail.blocked = true; 3250 | window.setTimeout(function () { 3251 | sequence.tail.blocked = false; 3252 | animate.call(this$1, nextElement, true); 3253 | }, sequence.interval); 3254 | } 3255 | } 3256 | 3257 | var polyfill = (function () { 3258 | var clock = Date.now(); 3259 | 3260 | return function (callback) { 3261 | var currentTime = Date.now(); 3262 | if (currentTime - clock > 16) { 3263 | clock = currentTime; 3264 | callback(currentTime); 3265 | } else { 3266 | setTimeout(function () { return polyfill(callback); }, 0); 3267 | } 3268 | } 3269 | })(); 3270 | 3271 | 3272 | var requestAnimationFrame = window.requestAnimationFrame 3273 | || window.webkitRequestAnimationFrame 3274 | || window.mozRequestAnimationFrame 3275 | || polyfill; 3276 | 3277 | function delegate (event) { 3278 | var this$1 = this; 3279 | if ( event === void 0 ) event = {}; 3280 | 3281 | requestAnimationFrame(function () { 3282 | var containers = this$1.store.containers; 3283 | var elements = this$1.store.elements; 3284 | 3285 | switch (event.type) { 3286 | 3287 | case 'scroll': 3288 | each(containers, function (container) { return container.scroll = getScrolled.call(this$1, container); }); 3289 | each(elements, function (element) { return animate.call(this$1, element); }); 3290 | break 3291 | 3292 | case 'resize': 3293 | default: 3294 | each(containers, function (container) { 3295 | container.geometry = getGeometry.call(this$1, container, /* isContainer: */ true); 3296 | container.scroll = getScrolled.call(this$1, container); 3297 | }); 3298 | each(elements, function (element) { 3299 | element.geometry = getGeometry.call(this$1, element); 3300 | animate.call(this$1, element); 3301 | }); 3302 | } 3303 | 3304 | this$1.pristine = false; 3305 | }); 3306 | } 3307 | 3308 | var version = "4.0.0-beta.9"; 3309 | 3310 | function ScrollReveal (options) { 3311 | var this$1 = this; 3312 | if ( options === void 0 ) options = {}; 3313 | 3314 | 3315 | /** 3316 | * Support instantiation without the `new` keyword. 3317 | */ 3318 | if (typeof this === 'undefined' || Object.getPrototypeOf(this) !== ScrollReveal.prototype) { 3319 | return new ScrollReveal(options) 3320 | } 3321 | 3322 | var _debug = false; 3323 | Object.defineProperty(this, 'debug', { 3324 | get: function () { return _debug; }, 3325 | set: function (value) { 3326 | if (typeof value === 'boolean') { _debug = value; } 3327 | }, 3328 | }); 3329 | 3330 | if (!ScrollReveal.isSupported()) { 3331 | logger.call(this, 'Instantiation aborted.', 'This browser is not supported.'); 3332 | return noop 3333 | } 3334 | 3335 | try { 3336 | Object.defineProperty(this, 'defaults', { 3337 | get: (function () { 3338 | var config = {}; 3339 | deepAssign(config, defaults, options); 3340 | return function () { return config; } 3341 | })(), 3342 | }); 3343 | } catch (e) { 3344 | logger.call(this, 'Instantiation failed.', 'Invalid configuration.', e.message); 3345 | return noop 3346 | } 3347 | 3348 | try { 3349 | var container = getNode(this.defaults.container); 3350 | if (!container) { 3351 | throw new Error('Invalid container.') 3352 | } 3353 | } catch (e) { 3354 | logger.call(this, 'Instantiation failed.', e.message); 3355 | return noop 3356 | } 3357 | 3358 | if (this.defaults.mobile === isMobile() || this.defaults.desktop === !isMobile()) { 3359 | document.documentElement.classList.add('sr'); 3360 | } 3361 | 3362 | this.store = { 3363 | containers: {}, 3364 | elements: {}, 3365 | history: [], 3366 | sequences: {}, 3367 | }; 3368 | 3369 | this.pristine = true; 3370 | 3371 | Object.defineProperty(this, 'delegate', { get: function () { return delegate.bind(this$1); } }); 3372 | Object.defineProperty(this, 'version', { get: function () { return version; } }); 3373 | Object.defineProperty(this, 'noop', { get: function () { return false; } }); 3374 | } 3375 | 3376 | ScrollReveal.isSupported = function () { return transformSupported() && transitionSupported(); }; 3377 | 3378 | ScrollReveal.prototype.clean = clean; 3379 | ScrollReveal.prototype.destroy = destroy; 3380 | ScrollReveal.prototype.reveal = reveal; 3381 | ScrollReveal.prototype.sync = sync; 3382 | 3383 | ///// ///// ///// ///// 3384 | ///// ///// ///// ///// 3385 | ///// ///// ///// ///// 3386 | ///// ///// ///// ///// 3387 | ///// ///// ///// 3388 | ///// ///// ///// 3389 | ///// ///// ///// ///// 3390 | ///// ///// ///// ///// 3391 | ///// ///// 3392 | ///// ///// 3393 | ///// ///// ///// ///// 3394 | ///// ///// ///// ///// 3395 | ///// ///// ///// ///// 3396 | ///// ///// ///// ///// 3397 | 3398 | /*! 3399 | * ScrollReveal 3400 | * ------------ 3401 | * Website : https://scrollrevealjs.org 3402 | * Support : https://github.com/jlmakes/scrollreveal/issues 3403 | * Author : https://twitter.com/jlmakes 3404 | * 3405 | * Licensed under the GNU General Public License 3.0 for 3406 | * compatible open source projects and non-commercial use. 3407 | * 3408 | * For commercial sites, themes, projects, and applications, 3409 | * keep your source code proprietary and please purchase a 3410 | * commercial license from https://scrollrevealjs.org 3411 | * 3412 | * Copyright (c) 2014–2017 Julian Lloyd. All rights reserved. 3413 | */ 3414 | 3415 | return ScrollReveal; 3416 | 3417 | }))); 3418 | }); 3419 | 3420 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { 3421 | return typeof obj; 3422 | } : function (obj) { 3423 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 3424 | }; 3425 | 3426 | 3427 | 3428 | 3429 | 3430 | 3431 | 3432 | 3433 | 3434 | 3435 | 3436 | var classCallCheck = function (instance, Constructor) { 3437 | if (!(instance instanceof Constructor)) { 3438 | throw new TypeError("Cannot call a class as a function"); 3439 | } 3440 | }; 3441 | 3442 | var createClass = function () { 3443 | function defineProperties(target, props) { 3444 | for (var i = 0; i < props.length; i++) { 3445 | var descriptor = props[i]; 3446 | descriptor.enumerable = descriptor.enumerable || false; 3447 | descriptor.configurable = true; 3448 | if ("value" in descriptor) descriptor.writable = true; 3449 | Object.defineProperty(target, descriptor.key, descriptor); 3450 | } 3451 | } 3452 | 3453 | return function (Constructor, protoProps, staticProps) { 3454 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 3455 | if (staticProps) defineProperties(Constructor, staticProps); 3456 | return Constructor; 3457 | }; 3458 | }(); 3459 | 3460 | 3461 | 3462 | 3463 | 3464 | 3465 | 3466 | var _extends = Object.assign || function (target) { 3467 | for (var i = 1; i < arguments.length; i++) { 3468 | var source = arguments[i]; 3469 | 3470 | for (var key in source) { 3471 | if (Object.prototype.hasOwnProperty.call(source, key)) { 3472 | target[key] = source[key]; 3473 | } 3474 | } 3475 | } 3476 | 3477 | return target; 3478 | }; 3479 | 3480 | 3481 | 3482 | var inherits = function (subClass, superClass) { 3483 | if (typeof superClass !== "function" && superClass !== null) { 3484 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 3485 | } 3486 | 3487 | subClass.prototype = Object.create(superClass && superClass.prototype, { 3488 | constructor: { 3489 | value: subClass, 3490 | enumerable: false, 3491 | writable: true, 3492 | configurable: true 3493 | } 3494 | }); 3495 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 3496 | }; 3497 | 3498 | 3499 | 3500 | 3501 | 3502 | 3503 | 3504 | 3505 | 3506 | 3507 | 3508 | var possibleConstructorReturn = function (self, call) { 3509 | if (!self) { 3510 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 3511 | } 3512 | 3513 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 3514 | }; 3515 | 3516 | /** 3517 | * 3518 | * @param {array|object} scrollRevealOptions 3519 | * @constructor 3520 | */ 3521 | var ReactScrollreveal = function ReactScrollreveal() { 3522 | var scrollRevealOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 3523 | return function (Component) { 3524 | var sr = scrollreveal(); 3525 | 3526 | var ComponentWithScrollReveal = function (_Component) { 3527 | inherits(ComponentWithScrollReveal, _Component); 3528 | 3529 | function ComponentWithScrollReveal() { 3530 | var _ref; 3531 | 3532 | var _temp, _this, _ret; 3533 | 3534 | classCallCheck(this, ComponentWithScrollReveal); 3535 | 3536 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 3537 | args[_key] = arguments[_key]; 3538 | } 3539 | 3540 | return _ret = (_temp = (_this = possibleConstructorReturn(this, (_ref = ComponentWithScrollReveal.__proto__ || Object.getPrototypeOf(ComponentWithScrollReveal)).call.apply(_ref, [this].concat(args))), _this), _this.forEachRevealElement = function (fn) { 3541 | if (Array.isArray(scrollRevealOptions)) { 3542 | scrollRevealOptions.forEach(function (options) { 3543 | fn(options); 3544 | }); 3545 | } else if ((typeof scrollRevealOptions === 'undefined' ? 'undefined' : _typeof(scrollRevealOptions)) === 'object') { 3546 | fn(scrollRevealOptions); 3547 | } else { 3548 | throw new TypeError('Invalid arguments were passed'); 3549 | } 3550 | }, _this.applyRevealAnimation = function (_ref2) { 3551 | var selector = _ref2.selector, 3552 | _ref2$options = _ref2.options, 3553 | options = _ref2$options === undefined ? {} : _ref2$options, 3554 | interval = _ref2.interval; 3555 | 3556 | var revealElements = _this.getRevealElements(selector); 3557 | var opts = Object.assign({}, options); 3558 | 3559 | // TODO check nodeType check 3560 | if (revealElements.length || !!revealElements.nodeType) { 3561 | sr.reveal(revealElements, opts, interval); 3562 | } 3563 | }, _this.clearElementsSrInitiation = function (_ref3) { 3564 | var selector = _ref3.selector; 3565 | 3566 | var revealElements = Array.prototype.slice.apply(_this.getRevealElements(selector)); 3567 | 3568 | if (revealElements.length || !!revealElements.nodeType) { 3569 | revealElements.forEach(function (node) { 3570 | node.removeAttribute('style'); 3571 | node.removeAttribute('data-sr-id'); 3572 | }); 3573 | } 3574 | }, _this.getComponentRef = function (node) { 3575 | // TODO: make sure we can or can't avoid setting block ref inside child Component 3576 | if (!node) { 3577 | _this.block = node; 3578 | } else { 3579 | _this.block = node.refs.block; 3580 | } 3581 | }, _temp), possibleConstructorReturn(_this, _ret); 3582 | } 3583 | 3584 | // TODO rename it, make real forEachRevealElement function 3585 | /** 3586 | * Iterates through all scrollRevealOptions and applies given function 3587 | * 3588 | * @param {function} fn 3589 | * @return undefined 3590 | */ 3591 | 3592 | 3593 | createClass(ComponentWithScrollReveal, [{ 3594 | key: 'getRevealElements', 3595 | 3596 | 3597 | /** 3598 | * Get reveal elements by given selector 3599 | * 3600 | * @param {string} selector 3601 | * @return {NodeList} 3602 | */ 3603 | value: function getRevealElements(selector) { 3604 | return !!selector ? this.block.querySelectorAll(selector) : this.block; 3605 | } 3606 | 3607 | /** 3608 | * Init scrollreveal for all releveal elements by selector 3609 | * 3610 | * @param {string} selector - selector that gets elements to reveal 3611 | * @param {object} options - ScrollReveal's options (see https://github.com/jlmakes/scrollreveal#2-configuration) 3612 | * @param {number} interval - ScrollReveal's interval value to make sequential animation 3613 | */ 3614 | 3615 | }, { 3616 | key: 'initialize', 3617 | 3618 | 3619 | /** 3620 | * Initialize sr animations for every reveal element by given selector 3621 | * 3622 | * @return undefined 3623 | */ 3624 | value: function initialize() { 3625 | if (!this.block) { 3626 | return; 3627 | } 3628 | 3629 | this.forEachRevealElement(this.applyRevealAnimation); 3630 | } 3631 | }, { 3632 | key: 'clear', 3633 | value: function clear(clearStyles) { 3634 | // clearing styles makes sr animation initialize again 3635 | // on same element that were still in DOM 3636 | if (clearStyles) { 3637 | this.forEachRevealElement(this.clearElementsSrInitiation); 3638 | } 3639 | 3640 | // remove event listeners 3641 | // on component unmount event 3642 | sr.destroy(); 3643 | } 3644 | }, { 3645 | key: 'refresh', 3646 | value: function refresh() { 3647 | this.clear(true); 3648 | this.init(); 3649 | } 3650 | }, { 3651 | key: 'componentDidMount', 3652 | value: function componentDidMount() { 3653 | this.initialize(); 3654 | } 3655 | }, { 3656 | key: 'componentWillUpdate', 3657 | value: function componentWillUpdate() { 3658 | this.refresh(); 3659 | } 3660 | }, { 3661 | key: 'componentWillUnmount', 3662 | value: function componentWillUnmount() { 3663 | this.clear(); 3664 | } 3665 | }, { 3666 | key: 'render', 3667 | value: function render() { 3668 | return index.createElement(Component, _extends({ ref: this.getComponentRef, sr: sr }, this.props)); 3669 | } 3670 | }]); 3671 | return ComponentWithScrollReveal; 3672 | }(Component); 3673 | 3674 | ComponentWithScrollReveal.displayName = 'ComponentWithScrollReveal'; 3675 | 3676 | 3677 | return ComponentWithScrollReveal; 3678 | }; 3679 | }; 3680 | 3681 | export default ReactScrollreveal; 3682 | //# sourceMappingURL=react-scrollreveal.esm.js.map 3683 | -------------------------------------------------------------------------------- /docs/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require, import/no-unresolved, react/no-multi-comp, max-len, no-undef, semi, react/prop-types */ 2 | import React from 'react' 3 | import { render } from 'react-dom' 4 | import withScrollReveal from '../src/index' 5 | import './main.css' 6 | 7 | const WallOfText = ({ animationContainerReference }) => ( 8 |
9 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto, labore quo? Dolor eius 10 | neque odit quis quo. Adipisci corporis dolorem fugit id, laboriosam minima odio porro quibusdam repudiandae sit, 11 | tempore, ut voluptas? Amet consequatur earum itaque natus quia totam ullam. Autem doloremque esse impedit 12 | laudantium nobis perferendis soluta totam vero?

13 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias aliquid amet animi aperiam 14 | assumenda atque aut commodi consequuntur distinctio dolore earum eligendi esse et eum expedita hic illo in 15 | inventore itaque, labore laboriosam magnam nam neque nesciunt nisi perspiciatis porro, quia, ratione reiciendis 16 | reprehenderit sit tempora tenetur velit. Aperiam, quasi!

17 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias consectetur distinctio 18 | harum molestias nesciunt vel velit. Deserunt facilis iusto libero quo ut! A ab accusamus at commodi deleniti 19 | dolorem eaque error explicabo facere illo maxime numquam omnis perspiciatis placeat recusandae reprehenderit 20 | repudiandae sed similique sit, sunt temporibus tenetur vitae voluptatem!

21 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci aliquam aspernatur 22 | blanditiis consectetur cum distinctio dolor dolorem doloremque dolorum earum error esse et explicabo fugiat 23 | ipsum, laborum libero molestiae nihil nulla obcaecati provident quidem quos reiciendis rem repellat repellendus 24 | tenetur unde ut vero voluptatum? Aliquam, delectus, nemo. Esse, sunt, voluptas.

25 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dignissimos dolorem doloremque, 26 | eum ipsam magnam natus numquam officiis praesentium quo veniam. Accusantium autem commodi cum, dolorum error ex 27 | expedita hic iure iusto maxime mollitia neque nulla temporibus veritatis voluptate. At cupiditate dolores 28 | mollitia quasi rerum veritatis voluptas. Ex laudantium magni quod!

29 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid aperiam aspernatur 30 | blanditiis consequatur culpa cupiditate deserunt dolor, doloremque eaque eos ex facere illum in labore 31 | laboriosam, minima nemo nulla pariatur provident quae quasi quia quo rem repudiandae sequi sint ut veniam vero 32 | voluptatem voluptates. Cumque laboriosam laborum natus porro vero!

33 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias dolore ipsum molestias 34 | provident rem voluptate. Accusantium adipisci animi aperiam est facere incidunt ipsa magni nemo neque odio odit 35 | placeat quaerat quam, soluta veritatis. Dicta dignissimos esse, harum libero minus nulla praesentium quaerat 36 | quibusdam quisquam reiciendis repellat sed, temporibus ullam unde.

37 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus alias beatae delectus 38 | doloribus ea eligendi est maiores minima non officia, quidem reiciendis sint, voluptate. Consequuntur error nisi 39 | omnis perspiciatis quaerat. Cum facilis odit repellat totam voluptas. Architecto aut delectus dolore dolorum, et 40 | fugiat libero nam quae quis quisquam, voluptates voluptatibus.

41 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab accusantium ad aliquam, 42 | asperiores atque consequuntur, corporis ea est et itaque maxime, minus nemo odit quos ut vel voluptatem? Commodi 43 | deleniti dicta dolores dolorum earum enim fugit inventore maiores molestiae odio pariatur quibusdam quos 44 | reiciendis sint, soluta sunt tempore vitae voluptatum?

45 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab animi atque, earum enim est 46 | excepturi facilis fugit id illo itaque libero magni modi non, nulla obcaecati officia officiis omnis pariatur 47 | porro quis reiciendis repudiandae similique soluta suscipit voluptatum? Culpa debitis placeat quo repellat ullam 48 | veniam. Dolorum expedita natus sint voluptatum.

49 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad amet cupiditate et eveniet 50 | quasi? Aliquid amet cupiditate distinctio dolorum eos est fugit illo impedit labore laudantium non quasi quo, 51 | quod sapiente similique sint tempora! Amet beatae dolorem doloribus ea facilis fugit impedit incidunt labore 52 | quaerat, quibusdam, quisquam rem repellat tempore?

53 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium, adipisci aut 54 | consectetur consequatur consequuntur deleniti doloremque ea earum, eum excepturi harum impedit nisi porro quas 55 | qui similique, vel. Aliquid aut culpa eos explicabo hic, impedit in incidunt ipsa itaque mollitia officiis 56 | pariatur quos recusandae, sequi sit totam voluptate voluptates. Odit.

57 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ducimus explicabo id nostrum 58 | officiis quaerat qui quibusdam ut. Aliquam beatae consequuntur dolore eligendi esse et excepturi fugit illum, 59 | incidunt inventore ipsam necessitatibus, nisi odit temporibus voluptates! Accusantium, aliquam assumenda atque 60 | corporis exercitationem, impedit ipsam maxime neque nulla optio quasi reiciendis voluptate.

61 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. 62 | Architecto aut distinctio ducimus earum eum exercitationem explicabo officiis reiciendis, repudiandae. Atque 63 | dolor eius inventore ipsam laudantium modi nesciunt optio ratione vero?

64 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. 65 | Accusantium corporis, eius enim et facilis harum illum inventore, iure, maiores nesciunt non nostrum officia 66 | perferendis quae quas reiciendis repellat sint voluptatem.

67 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. 68 | Alias architecto atque culpa eaque eos et, excepturi illo incidunt minus perspiciatis sapiente sit tempora 69 | tenetur vero voluptas. Corporis incidunt iusto sed.

70 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. 71 | Amet aspernatur commodi culpa dolor eaque expedita laboriosam magnam molestiae mollitia neque officia optio 72 | possimus quas, quidem quos temporibus tenetur vel vero!

73 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque delectus ea illo impedit, 74 | pariatur quibusdam quisquam repellendus. Aliquam asperiores aut beatae commodi dolorem ea et, illo incidunt 75 | ipsum magni ratione sapiente sit soluta? Architecto beatae consequuntur corporis deserunt earum, ex facere 76 | facilis illum in ipsum, itaque perferendis reprehenderit ut voluptas?

77 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae dolores magnam repudiandae 78 | sit? Aut autem consequuntur, earum iusto non ullam! Accusamus, aliquam animi, at delectus eaque hic id ipsa 79 | itaque, laborum molestias nobis praesentium quam quas sint tempore. Aliquid, asperiores autem dolorum facere 80 | harum maxime nemo optio reiciendis repellendus vero?

81 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto asperiores delectus 82 | doloremque eum fugiat illum incidunt iste, maxime minima minus nesciunt nostrum nulla numquam optio perspiciatis 83 | praesentium quisquam, quos, recusandae rerum soluta suscipit voluptates voluptatum? Aspernatur blanditiis 84 | consectetur tempora vel! Alias dolorum nulla perferendis placeat quia repellat voluptas. Ex, pariatur.

85 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae corporis deleniti dolore 86 | dolores eos error eum fuga fugit, illum inventore labore modi nisi non nulla perferendis quas quo quos ratione 87 | totam, vitae! Ad doloremque doloribus quae? Alias facere impedit laborum, maiores qui recusandae reiciendis 88 | tenetur? Ab cupiditate natus nihil voluptas?

89 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias assumenda aut culpa 90 | distinctio, explicabo illo in inventore iste laborum magni minus mollitia neque nostrum numquam odio officiis 91 | placeat quas quasi qui quibusdam quisquam quod rem repellendus tempora unde ut vitae voluptates. Alias beatae 92 | cumque deleniti, dicta ipsa libero nesciunt repudiandae.

93 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet atque aut culpa ipsam iure 94 | magni necessitatibus, officiis repellat sed tempore? Atque blanditiis dolores doloribus, error id in ipsum iste 95 | itaque minima numquam optio quia voluptate? Ab consectetur eius fugit iste nisi! Alias autem explicabo neque, 96 | optio similique veniam voluptate. Maxime?

97 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem blanditiis cupiditate 98 | dolorem, eligendi iusto laudantium magni minima nobis nostrum possimus, quos reiciendis repudiandae tempora 99 | ullam unde veniam veritatis. Accusamus aliquid asperiores atque, corporis dolor doloremque dolorum eaque error 100 | et hic illo molestiae natus possimus provident quae quam rem sapiente voluptas?

101 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Explicabo fugiat harum illum 102 | natus necessitatibus nobis suscipit velit? Amet architecto deleniti dignissimos explicabo harum ipsum, 103 | laudantium libero nemo obcaecati odit provident, recusandae reprehenderit vitae. A inventore libero officiis 104 | temporibus voluptatem! Alias aut dicta distinctio ipsum laboriosam magnam maiores nemo nisi quasi?

105 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam asperiores assumenda 106 | atque consequuntur eligendi fuga, fugit id magnam magni maxime, obcaecati officia perferendis praesentium quia 107 | quis quod repellat, reprehenderit rerum similique sunt? Cum, dicta dolore eaque id iure nisi reprehenderit. 108 | Aliquam illum laborum nostrum quaerat velit veniam. Aliquam, dignissimos, soluta.

109 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur doloribus, eius ipsa 110 | magnam magni natus nisi nulla praesentium voluptatem voluptates. Ab amet atque, blanditiis culpa deleniti 111 | doloremque ducimus eos error expedita harum libero, maxime modi officiis provident, tenetur totam voluptatum. A, 112 | dolor doloribus exercitationem facere inventore nisi quos saepe voluptatibus!

113 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsum, nobis temporibus. Animi 114 | dolor earum eveniet illo incidunt laborum magnam nemo nobis perspiciatis porro, praesentium quaerat sequi 115 | tempora! A amet soluta sunt ut voluptas. Ad, architecto blanditiis, cum delectus dolores in nemo, obcaecati odio 116 | qui quidem quo quod repellendus unde. Quae?

117 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto dolores possimus quam 118 | tenetur. A aliquam aperiam dolorem doloremque eos esse, est harum illum, ipsam maiores molestiae, neque 119 | obcaecati perferendis praesentium provident quae quia quos ut? Alias asperiores assumenda corporis hic maiores, 120 | nihil non tempora. A distinctio doloremque numquam tempore velit?

121 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores dolor ex labore 122 | quisquam sunt! Accusantium alias aliquam assumenda beatae commodi consequatur cumque deserunt, distinctio dolor 123 | dolorem doloremque fuga fugiat id impedit ipsam iste itaque iure nam nostrum, numquam odio omnis optio 124 | praesentium quae quaerat quisquam sint suscipit unde vero voluptatum!

125 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad amet atque autem consequatur 126 | culpa cumque deserunt distinctio doloremque error ex expedita explicabo, fugit, in incidunt maxime, molestias 127 | nam neque officiis quas quasi qui quia reiciendis similique sit tenetur! Accusantium architecto aut deleniti 128 | dolor eaque ipsam mollitia provident quasi sint ullam!

129 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. A assumenda at dolor harum modi 130 | nisi quibusdam quos. Consectetur dicta distinctio eos facere minus modi natus non sapiente veritatis? Aliquid, 131 | consequuntur, deleniti dignissimos esse fuga labore laudantium minima nisi nostrum nulla officia officiis 132 | perspiciatis quidem quos saepe, suscipit unde veritatis voluptate!

133 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet autem deleniti dicta earum 134 | eius excepturi, exercitationem molestiae nisi quae quibusdam repellat sed. Dignissimos dolores, ducimus et in 135 | nihil quisquam rerum! Consequuntur ex iste neque quas vitae. Alias assumenda doloribus dolorum exercitationem, 136 | in minima obcaecati, porro quaerat quos, rerum ut veritatis?

137 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab accusamus consequatur debitis 138 | dolor doloribus esse eveniet exercitationem illo ipsa nesciunt, nisi nobis nulla numquam perspiciatis placeat 139 | ullam vero voluptas voluptate. Amet blanditiis cupiditate debitis doloribus et eveniet in, magni maxime minima 140 | praesentium sequi sit, unde voluptatibus. Consectetur deserunt laboriosam temporibus.

141 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci aliquid consequuntur 142 | cumque distinctio dolore id incidunt praesentium sequi voluptate voluptates? A ad aperiam distinctio doloribus 143 | error et inventore, modi perferendis quae qui tempora ut, velit vero? Atque molestias natus porro quisquam rem 144 | sunt? Ab accusamus delectus ipsa labore possimus ut!

145 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. A adipisci aperiam asperiores 146 | aspernatur assumenda commodi consequatur consequuntur culpa cum debitis deleniti dolores ea est et ex fugiat 147 | fugit id iste iure libero maiores nostrum obcaecati quod ratione, sapiente sit temporibus vel? Enim ex ipsum 148 | iusto laborum provident quidem quis quisquam.

149 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur beatae consequuntur 150 | corporis delectus distinctio, eius error explicabo fugiat illo labore libero modi, molestiae mollitia officia 151 | optio pariatur quam quis quos rerum soluta? Atque delectus, minus nobis officiis repudiandae temporibus? 152 | Adipisci animi dignissimos esse facere illo ipsa odio quae temporibus voluptate!

153 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet at autem beatae corporis cum 154 | dolor, ea explicabo inventore ipsum magni mollitia nemo nihil, quam quibusdam voluptates. Adipisci animi 155 | asperiores cum delectus dolor, dolore, ex exercitationem hic in iure labore mollitia odit quam ratione tempora 156 | vel voluptatem! Incidunt non quo sapiente.

157 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, aperiam asperiores 158 | blanditiis eius eum excepturi expedita facere fuga fugit illo inventore natus nemo neque officiis placeat 159 | recusandae reiciendis rem similique sit totam? Autem beatae consectetur, consequatur earum, enim eos laborum 160 | nemo neque perferendis porro quis reprehenderit sunt tempore? Odio, voluptatibus.

161 |
162 | ); 163 | 164 | const WrappedComponent = withScrollReveal([ 165 | { 166 | selector: '.sr-item', 167 | options: { 168 | reset: true 169 | } 170 | }, 171 | { 172 | selector: '.sr-item--sequence', 173 | options: { 174 | reset: true, 175 | delay: 400 176 | }, 177 | interval: 100 178 | } 179 | ])(WallOfText); 180 | 181 | render( 182 | , 183 | document.getElementById('app') 184 | ); 185 | -------------------------------------------------------------------------------- /docs/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | -webkit-font-smoothing: antialiased; 3 | -moz-font-smoothing: antialiased; 4 | } 5 | 6 | .col { 7 | width: 25%; 8 | float: left; 9 | } 10 | 11 | .container { 12 | width: 800px; 13 | margin: 0 auto; 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-scrollreveal", 3 | "description": "React HOC wrapper for scrollreveal library", 4 | "author": "Rusinov Anton", 5 | "version": "1.2.0", 6 | "scripts": { 7 | "start": "webpack-dev-server --env dev", 8 | "test": "jest", 9 | "test:coverage": "jest --coverage", 10 | "test:watch": "jest --watch", 11 | "test:lint": "eslint . --ignore-path .gitignore --cache", 12 | "gh-pages": "webpack --env ghPages", 13 | "gh-pages:deploy": "npx gh-pages -d gh-pages", 14 | "gh-pages:stats": "webpack --env ghPages --profile --json > stats.json", 15 | "build": "npm run dist", 16 | "dist": "webpack --env dist", 17 | "dist:es6": "rimraf ./dist-es6 && BABEL_ENV=es6 babel ./src --out-dir ./dist-es6", 18 | "dist:min": "webpack --env distMin", 19 | "dist:modules": "rimraf ./dist-modules && BABEL_ENV=modules babel ./src --out-dir ./dist-modules", 20 | "preversion": "npm run test && npm run dist && npm run dist:min && git commit --allow-empty -am \"Update dist\"", 21 | "prepublish": "npm run dist:es6 && npm run dist:modules", 22 | "postpublish": "npm run gh-pages && npm run gh-pages:deploy" 23 | }, 24 | "main": "dist-modules", 25 | "module": "dist-es6", 26 | "jsnext:main": "dist-es6", 27 | "devDependencies": { 28 | "babel-cli": "^6.26.0", 29 | "babel-core": "^6.26.3", 30 | "babel-eslint": "^7.2.3", 31 | "babel-jest": "^20.0.3", 32 | "babel-loader": "^7.0.0", 33 | "babel-plugin-transform-class-properties": "^6.24.1", 34 | "babel-plugin-transform-react-remove-prop-types": "^0.4.4", 35 | "babel-preset-es2015": "^6.24.1", 36 | "babel-preset-react": "^6.24.1", 37 | "babel-preset-react-hmre": "^1.1.1", 38 | "catalog": "^2.5.3", 39 | "clean-webpack-plugin": "^0.1.16", 40 | "css-loader": "^0.28.1", 41 | "eslint": "^3.19.0", 42 | "eslint-config-airbnb": "^14.1.0", 43 | "eslint-loader": "^1.7.1", 44 | "eslint-plugin-import": "^2.2.0", 45 | "eslint-plugin-jsx-a11y": "^4.0.0", 46 | "eslint-plugin-react": "^6.9.0", 47 | "extract-text-webpack-plugin": "^2.1.0", 48 | "file-loader": "^0.11.1", 49 | "gh-pages": "^0.12.0", 50 | "git-prepush-hook": "^1.0.2", 51 | "html-webpack-plugin": "^2.28.0", 52 | "html-webpack-template": "^6.0.1", 53 | "jest": "^23.4.2", 54 | "jsdom": "^11.12.0", 55 | "json-loader": "^0.5.4", 56 | "purecss": "^0.6.2", 57 | "raf": "^3.3.2", 58 | "raw-loader": "^0.5.1", 59 | "react": "^16.4.2", 60 | "react-dom": "^16.4.2", 61 | "react-github-corner": "^0.3.0", 62 | "react-test-renderer": "^16.0.0-beta.2", 63 | "rimraf": "^2.6.2", 64 | "scrollreveal": "^4.0.0", 65 | "style-loader": "^0.17.0", 66 | "system-bell-webpack-plugin": "^1.0.0", 67 | "url-loader": "^1.0.1", 68 | "webpack": "^2.7.0", 69 | "webpack-dev-server": "^2.4.5", 70 | "webpack-merge": "^4.1.4" 71 | }, 72 | "repository": { 73 | "type": "git", 74 | "url": "https://github.com/RusinovAnton/react-scrollreveal.git" 75 | }, 76 | "bugs": { 77 | "url": "https://github.com/RusinovAnton/react-scrollreveal/issues" 78 | }, 79 | "jest": { 80 | "collectCoverage": true, 81 | "verbose": true, 82 | "runner": "jest-runner", 83 | "testURL": "http://localhost/", 84 | "moduleFileExtensions": [ 85 | "js", 86 | "jsx" 87 | ], 88 | "moduleDirectories": [ 89 | "node_modules", 90 | "packages" 91 | ] 92 | }, 93 | "keywords": [ 94 | "react", 95 | "reactjs", 96 | "scrollreveal", 97 | "animation" 98 | ], 99 | "license": "GPL-3.0", 100 | "pre-push": [ 101 | "test" 102 | ], 103 | "peerDependencies": { 104 | "react": "^16.4.2", 105 | "react-dom": "^16.4.2", 106 | "scrollreveal": "^4.0.0" 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' // eslint-disable-line semi 2 | import ScrollReveal from 'scrollreveal' // eslint-disable-line semi 3 | 4 | 5 | /** 6 | * Creates React Component that will have animated elements on scroll 7 | * 8 | * @param {Array|object} srOptions 9 | * @param {string} srOptions.selector 10 | * @param {object} srOptions.options 11 | * @param {number} srOptions.interval 12 | * @return {function} React component 13 | */ 14 | const ReactScrollreveal = (srOptions = {}) => (Component) => { 15 | const sr = ScrollReveal(); 16 | 17 | class ComponentWithScrollReveal extends React.Component { 18 | static displayName = 'ComponentWithScrollReveal'; 19 | 20 | componentDidMount() { 21 | this.initialize(); 22 | } 23 | 24 | componentWillUpdate() { 25 | this.refresh(); 26 | } 27 | 28 | componentWillUnmount() { 29 | this.clean(); 30 | } 31 | 32 | /** 33 | * 34 | * @param {function} fn 35 | */ 36 | forEachSrElement = (fn) => { 37 | const elements = []; 38 | 39 | this.forEachSrOption(({ selector }) => { 40 | elements.concat(Array.prototype.slice.apply(document.querySelectorAll(selector))); 41 | }); 42 | 43 | elements.forEach(fn); 44 | }; 45 | 46 | /** 47 | * Iterates through all srOptions and applies given function 48 | * 49 | * @param {function} fn 50 | * @return undefined 51 | */ 52 | forEachSrOption = (fn) => { 53 | if (Array.isArray(srOptions)) { 54 | srOptions.forEach((options) => { 55 | fn(options); 56 | }); 57 | } else if (typeof srOptions === 'object') { 58 | fn(srOptions); 59 | } else { 60 | throw new TypeError('Invalid arguments were passed'); 61 | } 62 | }; 63 | 64 | /** 65 | * Get reveal elements by given selector 66 | * 67 | * @param {string} selector 68 | * @return {NodeList} 69 | */ 70 | getRevealElements(selector) { 71 | return selector ? this.animationContainer.querySelectorAll(selector) : 72 | this.animationContainer; 73 | } 74 | 75 | /** 76 | * Init scrollreveal for all reveal elements by selector 77 | * 78 | * @param {number} interval - ScrollReveal's interval value to make sequential animation 79 | * @param {object} options - ScrollReveal's options (see https://github.com/jlmakes/scrollreveal#2-configuration) 80 | * @param {string} selector - selector that gets elements to reveal 81 | */ 82 | applyRevealAnimation = ({ selector, options = {}, interval }) => { 83 | const revealElements = this.getRevealElements(selector); 84 | const opts = Object.assign({}, options); 85 | 86 | // revealElements can be NodeList or single node 87 | if (revealElements.length || !!revealElements.nodeType) { 88 | sr.reveal(revealElements, opts, interval); 89 | } 90 | }; 91 | 92 | /** 93 | * Initialize sr animations for every reveal element by given selector 94 | * 95 | * @return undefined 96 | */ 97 | initialize() { 98 | if (!this.animationContainer) { 99 | return; 100 | } 101 | 102 | this.forEachSrOption(this.applyRevealAnimation); 103 | } 104 | 105 | clean(cleanStyles) { 106 | // cleaning styles makes sr animation initialize again 107 | // on same element that were still in DOM 108 | if (cleanStyles) { 109 | this.forEachSrElement(sr.clean); 110 | } else { 111 | // remove event listeners 112 | // on component unmount event 113 | sr.destroy(); 114 | } 115 | } 116 | 117 | refresh() { 118 | this.clean(true); 119 | this.initialize(); 120 | } 121 | 122 | /** 123 | * Gets ref to the child's component desired animation container DOM node 124 | * 125 | * @param {object} node 126 | * @return undefined 127 | */ 128 | getRef = (node) => { 129 | if (typeof node.nodeType === 'number') { 130 | this.animationContainer = node; 131 | } else { 132 | throw new Error('You should put animationContainerReference on DOM node, not React component.'); 133 | } 134 | }; 135 | 136 | render() { 137 | return ( 138 | 144 | ); 145 | } 146 | } 147 | 148 | return ComponentWithScrollReveal; 149 | }; 150 | 151 | export default ReactScrollreveal; 152 | -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import webpack from 'webpack'; 4 | import ExtractTextPlugin from 'extract-text-webpack-plugin'; 5 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 6 | import SystemBellPlugin from 'system-bell-webpack-plugin'; 7 | import CleanWebpackPlugin from 'clean-webpack-plugin'; 8 | import merge from 'webpack-merge'; 9 | 10 | const pkg = require('./package.json'); 11 | 12 | const ROOT_PATH = __dirname; 13 | const config = { 14 | paths: { 15 | dist: path.join(ROOT_PATH, 'dist'), 16 | src: path.join(ROOT_PATH, 'src'), 17 | docs: path.join(ROOT_PATH, 'docs'), 18 | ghPages: path.join(ROOT_PATH, 'gh-pages') 19 | }, 20 | filename: 'bundle', 21 | library: 'ReactScrollreveal' 22 | }; 23 | 24 | const common = { 25 | resolve: { 26 | extensions: ['.js', '.css', '.png', '.jpg'] 27 | }, 28 | module: { 29 | loaders: [ 30 | { 31 | test: /\.js$/, 32 | enforce: 'pre', 33 | use: 'eslint-loader', 34 | include: [ 35 | config.paths.docs, 36 | config.paths.src 37 | ] 38 | }, 39 | { 40 | test: /\.md$/, 41 | use: ['catalog/lib/loader', 'raw-loader'] 42 | }, 43 | { 44 | test: /\.(jpg|png)$/, 45 | use: { 46 | loader: 'url-loader', 47 | options: { 48 | limit: 10000 49 | } 50 | } 51 | } 52 | ] 53 | }, 54 | plugins: [ 55 | new SystemBellPlugin() 56 | ] 57 | }; 58 | 59 | const siteCommon = { 60 | plugins: [ 61 | new HtmlWebpackPlugin({ 62 | template: require('html-webpack-template'), // eslint-disable-line global-require 63 | inject: false, 64 | mobile: true, 65 | title: pkg.name, 66 | appMountId: 'app' 67 | }), 68 | new webpack.DefinePlugin({ 69 | NAME: JSON.stringify(pkg.name), 70 | USER: JSON.stringify(pkg.user), 71 | VERSION: JSON.stringify(pkg.version) 72 | }) 73 | ] 74 | }; 75 | 76 | const dev = merge(common, siteCommon, { 77 | devtool: 'eval-source-map', 78 | entry: { 79 | docs: [config.paths.docs] 80 | }, 81 | plugins: [ 82 | new webpack.DefinePlugin({ 83 | 'process.env.NODE_ENV': '"development"' 84 | }), 85 | new webpack.HotModuleReplacementPlugin() 86 | ], 87 | module: { 88 | loaders: [ 89 | { 90 | test: /\.css$/, 91 | use: ['style-loader', 'css-loader'] 92 | }, 93 | { 94 | test: /\.js$/, 95 | use: { 96 | loader: 'babel-loader', 97 | options: { 98 | cacheDirectory: true 99 | } 100 | }, 101 | include: [ 102 | config.paths.docs, 103 | config.paths.src 104 | ] 105 | } 106 | ] 107 | }, 108 | devServer: { 109 | historyApiFallback: true, 110 | hot: true, 111 | inline: true, 112 | host: process.env.HOST, 113 | port: process.env.PORT, 114 | stats: 'errors-only' 115 | } 116 | }); 117 | 118 | const ghPages = merge(common, siteCommon, { 119 | entry: { 120 | app: config.paths.docs 121 | }, 122 | output: { 123 | path: config.paths.ghPages, 124 | filename: '[name].[chunkhash].js', 125 | chunkFilename: '[chunkhash].js' 126 | }, 127 | plugins: [ 128 | new CleanWebpackPlugin(['gh-pages'], { 129 | verbose: false 130 | }), 131 | new ExtractTextPlugin('[name].[chunkhash].css'), 132 | new webpack.DefinePlugin({ 133 | // This affects the react lib size 134 | 'process.env.NODE_ENV': '"production"' 135 | }), 136 | new webpack.optimize.UglifyJsPlugin({ 137 | compress: { 138 | warnings: false 139 | } 140 | }), 141 | new webpack.optimize.CommonsChunkPlugin({ 142 | name: 'vendor', 143 | minChunks: ({ resource }) => ( 144 | resource && 145 | resource.indexOf('node_modules') >= 0 && 146 | resource.match(/\.js$/) 147 | ) 148 | }) 149 | ], 150 | module: { 151 | loaders: [ 152 | { 153 | test: /\.css$/, 154 | use: ExtractTextPlugin.extract({ 155 | fallback: 'style-loader', 156 | use: 'css-loader' 157 | }) 158 | }, 159 | { 160 | test: /\.js$/, 161 | use: 'babel-loader', 162 | include: [ 163 | config.paths.docs, 164 | config.paths.src 165 | ] 166 | } 167 | ] 168 | } 169 | }); 170 | 171 | const distCommon = { 172 | devtool: 'source-map', 173 | output: { 174 | path: config.paths.dist, 175 | libraryTarget: 'umd', 176 | library: config.library 177 | }, 178 | entry: config.paths.src, 179 | externals: { 180 | react: { 181 | commonjs: 'react', 182 | commonjs2: 'react', 183 | amd: 'React', 184 | root: 'React' 185 | } 186 | }, 187 | module: { 188 | loaders: [ 189 | { 190 | test: /\.js$/, 191 | use: 'babel-loader', 192 | include: config.paths.src 193 | } 194 | ] 195 | }, 196 | plugins: [ 197 | new SystemBellPlugin() 198 | ] 199 | }; 200 | 201 | const dist = merge(distCommon, { 202 | output: { 203 | filename: `${config.filename}.js` 204 | } 205 | }); 206 | 207 | const distMin = merge(distCommon, { 208 | output: { 209 | filename: `${config.filename}.min.js` 210 | }, 211 | plugins: [ 212 | new webpack.optimize.UglifyJsPlugin({ 213 | compress: { 214 | warnings: false 215 | } 216 | }) 217 | ] 218 | }); 219 | 220 | module.exports = (env) => { 221 | process.env.BABEL_ENV = env; 222 | 223 | const targets = { 224 | dev, 225 | dist, 226 | distMin, 227 | ghPages 228 | }; 229 | 230 | return targets[env] ? targets[env] : common; 231 | }; 232 | --------------------------------------------------------------------------------