├── .babelrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── README.md
├── __tests__
├── testAbTest.js
├── testExperimentClass.js
├── testNamespace.js
├── testParametrize.js
└── utils
│ └── experimentUtils.js
├── build.sh
├── build
├── index.js
├── webpack.config.js
└── webpack.config.minified.js
├── dist
├── react-experiments.js
└── react-experiments.min.js
├── examples
├── index.html
├── react-experiments.jpg
└── styles.css
├── package.json
└── src
├── Experiment.js
├── abtest.js
├── parametrize.js
├── parametrizeComponent.js
├── variationComponents.js
└── withExperimentParams.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | 'presets': ['react', 'stage-0', 'es2015', 'jest'],
3 | 'plugins': [
4 | "add-module-exports"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_store
2 | npm-debug.log
3 | node_modules/
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | - "6.1"
5 | - "5.11"
6 | - "4.0"
7 | script: npm run-script test
8 | before_script:
9 | - npm install
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes in 5.1.0
2 | - Require latest version of planout
3 |
4 | # Changes in 4.1.0
5 | - Now transpile using babel 6 instead of babel 4
6 |
7 | # Changes in 3.0.1
8 | - Removed the ```shouldEnroll``` prop. If you want to use conditional enrollment then you should register the experimental input to the experiment you care about and then conditionally unenroll users in your PlanOut experiment definition (see here for more information: https://github.com/HubSpot/PlanOut.js/pull/15)
9 |
10 | # Changes in 3.0
11 | - Renamed experimentClass -> Experiment
12 |
13 | # Changes in 2.1
14 | - Added the ```parametrize``` function that takes in experiment information and a component and parametrizes the component with the experiment parameters as props.
15 | - Added the requirement to pass in an array of experiment parameters as props to the Parametrize component and removed the experimentName prop.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-experiments
2 | [](https://travis-ci.org/rawls238/react-experiments)
3 | [](https://www.npmjs.com/package/react-experiments)
4 |
5 |
6 | ### This library is no longer actively maintained. ###
7 |
8 | react-experiments is a set of React components for implementing UI experiments.
9 |
10 | For additional context behind why we built this, check out the accompanying [blog post](http://product.hubspot.com/blog/product-experimentation-with-planout-and-react.js)
11 |
12 | # Installation
13 |
14 | ```
15 | npm install react-experiments
16 | ```
17 |
18 | # Usage
19 |
20 | **If you are using React 0.14 the latest supported version is 4.1.0**
21 |
22 | react-experiments was built to work with [PlanOut.js](https://www.github.com/HubSpot/PlanOut.js) and most of its constructs are inspired by the structure of PlanOut.js. This library will work out of the box if you pass it an instantiated PlanOut Namespace or Experiment class, but if you want to use your own methods of assigning experiment parameters and logging exposure then you can extend the base [experiment class](https://github.com/HubSpot/react-experiments/blob/master/src/Experiment.js) and pass that as the experiment class prop.
23 |
24 | ## Implementing a simple experiment
25 |
26 | This library serves as a way to declaratively implement UI experiments that are defined via PlanOut. The standard usage of this library is as follows:
27 |
28 | 1) Define experiment via PlanOut script / API. The PlanOut parameters that you set should map to the props on which you want to run an experiment. Let's use the [sample PlanOut.js experiment](https://github.com/HubSpot/PlanOut.js/blob/master/examples/sample_planout_es5.js#L41) as an example, which is effectively:
29 |
30 | ```js
31 | signupText = uniformChoice(choices=['Signup', 'Join now'])
32 | ```
33 |
34 | 2) Wrap the component where you want to implement your UI experiment with the parametrize function provided by the library along with an instantiated experiment class and the specific parameter names that you want to parametrize the component with. As an example,
35 |
36 | ```js
37 | const Signup = parametrize(DummyExperiment, ['signupText'], React.createClass({
38 | render() {
39 | return (
40 |
41 | {this.props.signupText}
42 |
43 | );
44 | }
45 | }));
46 | ```
47 |
48 | Now you should be all set to run the sample experiment. The Signup component will render 'Sign up' or 'Join now' based on the randomized parameter assigned by PlanOut.js.
49 |
50 | To put it all together,
51 |
52 | ```js
53 | exp = new DummyExperiment({ id: 'this_is_the_user_id'});
54 |
55 | let Signup = parametrize(exp, ['signupText'], React.createClass({
56 | render() {
57 | return (
58 |
59 | {this.props.signupText}
60 |
61 | );
62 | }
63 | }));
64 |
65 | let Parent = React.createClass({
66 | render() {
67 | ...
68 |
69 | }
70 | });
71 | ```
72 |
73 |
74 | ## Base Parametrize Component
75 |
76 | The implementation of all the components provided by this library are wrappers around a base ```Parametrize``` component. The ```Parametrize``` component allows for parametrizing a given component with experiment parameters. The following are the props that the ```Parametrize``` component takes:
77 |
78 | **experiment**: This is an instance of a PlanOut.js experiment/namespace class or the base Experiment class. [REQUIRED]
79 |
80 |
81 | **params**: This is the list of experiment parameters that you want to use to parametrize the component. They should correspond to the parameter names defined in your PlanOut script / experiment definition. [REQUIRED]
82 |
83 | [any arbitrary prop]: You can pass arbitrary props to the Parametrize component and they will be available via context.experimentProps in all descendants of the Parametrize component.
84 |
85 | ### Higher-order Parametrization Components
86 |
87 | There are two primary higher-order components to use for parametrization.
88 |
89 | **parametrize**: The ```parametrize``` function takes an instantiated experiment class, either an experiment name or a list of params, and a React component. It takes the given component and sets the deterministically and randomly assigned experiment parameters of the experiment class as props.
90 |
91 | ```parametrize(exp, ['signupText'], React.createClass({..}));```
92 |
93 | **withExperimentParams**: The ```withExperimentParams``` function is used in combination with the base ```Parametrize``` component. It is useful when running an experiment with nested components, but generally the ```parametrize``` function should be preferred.
94 |
95 |
96 | ```js
97 | const Parent = createReactClass({
98 | render() {
99 | return (
100 |
101 |
102 |
103 |
104 | );
105 | }
106 | });
107 |
108 | const SignupHeader = withExperimentParams(createReactClass({
109 | render() {
110 | return (
111 |
124 | );
125 | }
126 | });
127 | ```
128 |
129 |
130 | ## Running A/B Variation experiments:
131 |
132 | There are two common types of experimental parameters:
133 |
134 | 1) Parameters that correspond to parametrizations of existing variables and components. For instance, if one is running an experiment to test which shade of blue optimizes the click rate of the button, then the values to which your experiment parameters map would correspond to something such as the different hex codes for the different shades of blue.
135 |
136 | 2) "Branching" parameters where the parameter values correspond to different "variations" of the experiment. For instance, if one is testing two completely different user interfaces then it wouldn't make sense to parametrize every aspect that has changed, but rather to bin users into either 'Variation A' or 'Variation B'.
137 |
138 | While the core component of this library focuses on the first type of parameter, it also includes some convenience components built around the Parametrize component for running "branching" experiments using the ```ABTest``` component.
139 |
140 | ```javascript
141 |
142 |
143 | variation 1
144 |
145 |
146 | variation 2
147 |
148 |
149 | variation 3
150 |
151 |
152 | variation default
153 |
154 |
155 | ```
156 |
157 | The ABTest component above branches off the value of ```this.props.experiment.get(this.props.on);```, ```TestNamespace.get('foo')``` in this case, and renders the When component where ```ABTest.props.experiment.get(ABTest.props.on) === ABTest.props.value```. If it doesn't find a corresponding When component to render then the Default component will render. This component makes implementing an experiment using "branching" parameters easy.
158 |
159 | The ABTest component takes the following as props:
160 |
161 | **experiment** - an instantiated PlanOut namespace/experiment class or a custom Experiment class. [REQUIRED]
162 |
163 | **on** - the parameter name to "branch" off [REQUIRED]
164 |
165 | ## Customized Experiment Components
166 |
167 | If you want to create your own experiment component you can extend the base Parametrize component.
168 |
169 | ## Logging
170 |
171 | react-experiments deals with logging experiment exposure. All the components provided by this library trigger an exposure log when the component is mounted.
172 |
173 | ## Development
174 |
175 | This project is written using ES6 and all build steps / transpilation are done by webpack. Be sure to run ```npm install``` to install the necessary development dependencies. In order to develop and test locally, it is necessary to simply run the ```build.sh``` shell script which will take care of transpiling to ES5 and running tests.
176 |
177 | To test API changes locally, open the examples/index.html file locally after building with your most recent changes. The index.html file contains a simple example of using this library paired with the [PlanOut.js sample experiment](https://github.com/HubSpot/PlanOut.js/blob/master/examples/sample_planout_es5.js).
178 |
179 | Please be sure to add tests to this project when making changes. This project uses [Jest](https://facebook.github.io/jest/) for running tests. Tests can be run either by building the project using build.sh or by using ```npm test```.
180 |
--------------------------------------------------------------------------------
/__tests__/testAbTest.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TestUtils from 'react-dom/test-utils';
3 | import {DefaultExperiment, expInitializeObject, clearLogs, getLogLength} from './utils/experimentUtils';
4 | import ReactExperiments from '../dist/react-experiments';
5 |
6 | let exp;
7 | describe('Test experiment component', () => {
8 |
9 | beforeEach(() => {
10 | clearLogs();
11 | exp = new DefaultExperiment(expInitializeObject);
12 | });
13 |
14 | it('fetches the right value', () => {
15 | expect(exp.get('foo')).toEqual('Variation A');
16 | });
17 |
18 | it('renders only one, correct variation', () => {
19 | const experimentComponent = TestUtils.renderIntoDocument(
20 |
21 |
22 |
23 | foo
24 |
25 |
26 |
27 |
28 | foo
29 |
30 |
31 |
32 | );
33 |
34 | //renders only one variation
35 | expect(TestUtils.scryRenderedDOMComponentsWithClass(
36 | experimentComponent,
37 | 'experiment-variation-component'
38 | ).length).toBe(1);
39 |
40 | //renders the correct variation
41 | expect(TestUtils.scryRenderedDOMComponentsWithClass(
42 | experimentComponent,
43 | 'variation-a'
44 | ).length).toBe(1);
45 |
46 | expect(getLogLength()).toEqual(1);
47 | });
48 |
49 | it('renders the default variation when needed', () => {
50 | const experimentComponent = TestUtils.renderIntoDocument(
51 |
52 |
53 | foo
54 |
55 |
56 |
260 | );
261 | }
262 | }));
263 | const otherVal = 'ha';
264 | const parametrized = TestUtils.renderIntoDocument(
265 |
266 | );
267 | expect(getLogLength()).toEqual(0);
268 | expect(TestUtils.scryRenderedDOMComponentsWithClass(
269 | parametrized,
270 | exp.get('foo')
271 | ).length).toBe(0);
272 | });
273 | });
274 |
--------------------------------------------------------------------------------
/__tests__/utils/experimentUtils.js:
--------------------------------------------------------------------------------
1 | import {Experiment, Namespace, Ops} from 'planout';
2 |
3 | let globalLog = [];
4 | class DefaultExperiment extends Experiment {
5 | setup() {
6 | this.setName("SampleExperiment");
7 | }
8 |
9 | assign(params, args) {
10 | params.set('foo',
11 | new Ops.Random.UniformChoice({
12 | 'choices': ['Variation A', 'Variation B'],
13 | 'unit': args.id
14 | })
15 | );
16 |
17 | params.set('test2',
18 | new Ops.Random.UniformChoice({
19 | 'choices': ['Num1', 'Num2'],
20 | 'unit': args.id
21 | })
22 | );
23 | }
24 |
25 | configureLogger() {
26 | return;
27 | }
28 |
29 | log(stuff) {
30 | globalLog.push(stuff);
31 | }
32 |
33 | getParamNames() {
34 | return this.getDefaultParamNames();
35 | }
36 |
37 | previouslyLogged() {
38 | return this._exposureLogged;
39 | }
40 | };
41 |
42 | class DefaultExperiment2 extends Experiment {
43 | setup() {
44 | this.setName('SampleExperiment2');
45 | }
46 |
47 | assign(params, args) {
48 | params.set('foobar',
49 | new Ops.Random.UniformChoice({
50 | 'choices': ['Variation A', 'Variation B'],
51 | 'unit': args.id
52 | })
53 | );
54 | }
55 |
56 | configureLogger() {
57 | return;
58 | }
59 |
60 | log(stuff) {
61 | globalLog.push(stuff);
62 | }
63 |
64 | getParamNames() {
65 | return this.getDefaultParamNames();
66 | }
67 |
68 | previouslyLogged() {
69 | return this._exposureLogged;
70 | }
71 | }
72 |
73 | class DefaultNamespace extends Namespace.SimpleNamespace {
74 |
75 | setupDefaults() {
76 | this.numSegments = 100;
77 | }
78 |
79 | setup() {
80 | this.setName('MyNamespace');
81 | this.setPrimaryUnit('id');
82 | }
83 |
84 | setupExperiments() {
85 | this.addExperiment('SampleExperiment', DefaultExperiment, 50);
86 | this.addExperiment('SampleExperiment2', DefaultExperiment2, 50);
87 | }
88 | };
89 |
90 | class DefaultEmptyNamespace extends Namespace.SimpleNamespace {
91 |
92 | setupDefaults() {
93 | this.numSegments = 100;
94 | }
95 |
96 | setup() {
97 | this.setName('MyNamespace');
98 | this.setPrimaryUnit('id');
99 | }
100 |
101 | setupExperiments() {
102 | return;
103 | }
104 | };
105 |
106 |
107 | const expInitializeObject = { id: 2333 };
108 |
109 | const clearLogs = () => {
110 | globalLog = [];
111 | }
112 |
113 | const getLogLength = () => {
114 | return globalLog.length;
115 | }
116 |
117 | export default { DefaultExperiment, DefaultEmptyNamespace, DefaultNamespace, expInitializeObject, clearLogs, getLogLength };
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | node node_modules/webpack/bin/webpack --config build/webpack.config.js
2 | node node_modules/webpack/bin/webpack --config build/webpack.config.minified.js
3 |
--------------------------------------------------------------------------------
/build/index.js:
--------------------------------------------------------------------------------
1 | import * as Variations from '../src/variationComponents';
2 | import Experiment from '../src/Experiment';
3 | import ABTest from '../src/abtest';
4 | import Parametrize from '../src/parametrize';
5 | import withExperimentParams from '../src/withExperimentParams';
6 | import parametrize from '../src/parametrizeComponent';
7 |
8 | export default {
9 | ABTest: ABTest,
10 | When: Variations.When,
11 | Default: Variations.Default,
12 | Experiment: Experiment,
13 | Parametrize: Parametrize,
14 | withExperimentParams: withExperimentParams,
15 | parametrize: parametrize
16 | };
17 |
--------------------------------------------------------------------------------
/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './build/index.js',
3 | module: {
4 | loaders: [
5 | {
6 | test: /\.js$/,
7 | exclude: /node_modules/,
8 | loader: 'babel-loader',
9 | query: {
10 | cacheDirectory: true,
11 | presets: ['react', 'es2015', 'jest'],
12 | plugins: ['add-module-exports']
13 | }
14 | },
15 | ]
16 | },
17 | output: {
18 | filename: './dist/react-experiments.js',
19 | libraryTarget: 'umd',
20 | library: 'ReactExperiments'
21 | },
22 | externals: [
23 | {
24 | "react": {
25 | root: "React",
26 | commonjs2: "react",
27 | commonjs: "react",
28 | amd: "react"
29 | }
30 | }
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/build/webpack.config.minified.js:
--------------------------------------------------------------------------------
1 | var webpack = require("webpack");
2 |
3 | module.exports = {
4 | entry: './build/index.js',
5 | module: {
6 | loaders: [
7 | {
8 | test: /\.js$/,
9 | exclude: /node_modules/,
10 | loader: 'babel-loader',
11 | query: {
12 | cacheDirectory: true,
13 | presets: ['react', 'es2015', 'jest'],
14 | plugins: ['add-module-exports']
15 | }
16 | },
17 | ]
18 | },
19 | output: {
20 | filename: './dist/react-experiments.min.js',
21 | libraryTarget: 'umd',
22 | library: 'ReactExperiments'
23 | },
24 | plugins: [
25 | new webpack.optimize.UglifyJsPlugin({minimize: true})
26 | ],
27 | externals: [
28 | {
29 | "react": {
30 | root: "React",
31 | commonjs2: "react",
32 | commonjs: "react",
33 | amd: "react"
34 | }
35 | }
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/dist/react-experiments.js:
--------------------------------------------------------------------------------
1 | (function webpackUniversalModuleDefinition(root, factory) {
2 | if(typeof exports === 'object' && typeof module === 'object')
3 | module.exports = factory(require("react"));
4 | else if(typeof define === 'function' && define.amd)
5 | define(["react"], factory);
6 | else if(typeof exports === 'object')
7 | exports["ReactExperiments"] = factory(require("react"));
8 | else
9 | root["ReactExperiments"] = factory(root["React"]);
10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {
11 | return /******/ (function(modules) { // webpackBootstrap
12 | /******/ // The module cache
13 | /******/ var installedModules = {};
14 |
15 | /******/ // The require function
16 | /******/ function __webpack_require__(moduleId) {
17 |
18 | /******/ // Check if module is in cache
19 | /******/ if(installedModules[moduleId])
20 | /******/ return installedModules[moduleId].exports;
21 |
22 | /******/ // Create a new module (and put it into the cache)
23 | /******/ var module = installedModules[moduleId] = {
24 | /******/ exports: {},
25 | /******/ id: moduleId,
26 | /******/ loaded: false
27 | /******/ };
28 |
29 | /******/ // Execute the module function
30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31 |
32 | /******/ // Flag the module as loaded
33 | /******/ module.loaded = true;
34 |
35 | /******/ // Return the exports of the module
36 | /******/ return module.exports;
37 | /******/ }
38 |
39 |
40 | /******/ // expose the modules object (__webpack_modules__)
41 | /******/ __webpack_require__.m = modules;
42 |
43 | /******/ // expose the module cache
44 | /******/ __webpack_require__.c = installedModules;
45 |
46 | /******/ // __webpack_public_path__
47 | /******/ __webpack_require__.p = "";
48 |
49 | /******/ // Load entry module and return exports
50 | /******/ return __webpack_require__(0);
51 | /******/ })
52 | /************************************************************************/
53 | /******/ ([
54 | /* 0 */
55 | /***/ (function(module, exports, __webpack_require__) {
56 |
57 | 'use strict';
58 |
59 | Object.defineProperty(exports, "__esModule", {
60 | value: true
61 | });
62 |
63 | var _variationComponents = __webpack_require__(1);
64 |
65 | var Variations = _interopRequireWildcard(_variationComponents);
66 |
67 | var _Experiment = __webpack_require__(16);
68 |
69 | var _Experiment2 = _interopRequireDefault(_Experiment);
70 |
71 | var _abtest = __webpack_require__(17);
72 |
73 | var _abtest2 = _interopRequireDefault(_abtest);
74 |
75 | var _parametrize = __webpack_require__(18);
76 |
77 | var _parametrize2 = _interopRequireDefault(_parametrize);
78 |
79 | var _withExperimentParams = __webpack_require__(19);
80 |
81 | var _withExperimentParams2 = _interopRequireDefault(_withExperimentParams);
82 |
83 | var _parametrizeComponent = __webpack_require__(20);
84 |
85 | var _parametrizeComponent2 = _interopRequireDefault(_parametrizeComponent);
86 |
87 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
88 |
89 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
90 |
91 | exports.default = {
92 | ABTest: _abtest2.default,
93 | When: Variations.When,
94 | Default: Variations.Default,
95 | Experiment: _Experiment2.default,
96 | Parametrize: _parametrize2.default,
97 | withExperimentParams: _withExperimentParams2.default,
98 | parametrize: _parametrizeComponent2.default
99 | };
100 | module.exports = exports['default'];
101 |
102 | /***/ }),
103 | /* 1 */
104 | /***/ (function(module, exports, __webpack_require__) {
105 |
106 | 'use strict';
107 |
108 | Object.defineProperty(exports, "__esModule", {
109 | value: true
110 | });
111 | exports.Default = exports.When = undefined;
112 |
113 | var _react = __webpack_require__(2);
114 |
115 | var _react2 = _interopRequireDefault(_react);
116 |
117 | var _propTypes = __webpack_require__(3);
118 |
119 | var _propTypes2 = _interopRequireDefault(_propTypes);
120 |
121 | var _createReactClass = __webpack_require__(13);
122 |
123 | var _createReactClass2 = _interopRequireDefault(_createReactClass);
124 |
125 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
126 |
127 | var When = exports.When = (0, _createReactClass2.default)({
128 | displayName: 'When',
129 | getInitialState: function getInitialState() {
130 | return {
131 | shouldRender: false
132 | };
133 | },
134 |
135 |
136 | contextTypes: {
137 | experimentParameters: _propTypes2.default.object.isRequired,
138 | experimentProps: _propTypes2.default.object.isRequired
139 | },
140 |
141 | componentWillUpdate: function componentWillUpdate(props, state) {
142 | if (state.shouldRender) {
143 | this.context.experimentProps.enrolledInVariation();
144 | }
145 | },
146 | componentDidMount: function componentDidMount() {
147 | this.shouldRenderVariation();
148 | },
149 | shouldRenderVariation: function shouldRenderVariation() {
150 | var value = this.props.value;
151 | var paramName = this.context.experimentProps.on;
152 | if (this.context.experimentParameters && this.context.experimentParameters[paramName] === value) {
153 | this.setState({
154 | shouldRender: true
155 | });
156 | }
157 | },
158 | renderChildren: function renderChildren() {
159 | return _react2.default.Children.map(this.props.children, function (child) {
160 | if (_react2.default.isValidElement(child)) {
161 | return _react2.default.cloneElement(child, {});
162 | }
163 | return child;
164 | });
165 | },
166 | render: function render() {
167 | if (!this.state.shouldRender) {
168 | return null;
169 | }
170 |
171 | return _react2.default.createElement(
172 | 'span',
173 | { className: 'experiment-variation-component' },
174 | this.renderChildren()
175 | );
176 | }
177 | });
178 |
179 | var Default = exports.Default = (0, _createReactClass2.default)({
180 | displayName: 'Default',
181 |
182 | contextTypes: {
183 | experimentProps: _propTypes2.default.object.isRequired
184 | },
185 |
186 | render: function render() {
187 | if (this.context.experimentProps.hasRendered) {
188 | return null;
189 | }
190 |
191 | return _react2.default.createElement(
192 | 'span',
193 | null,
194 | this.props.children
195 | );
196 | }
197 | });
198 |
199 | /***/ }),
200 | /* 2 */
201 | /***/ (function(module, exports) {
202 |
203 | module.exports = __WEBPACK_EXTERNAL_MODULE_2__;
204 |
205 | /***/ }),
206 | /* 3 */
207 | /***/ (function(module, exports, __webpack_require__) {
208 |
209 | /* WEBPACK VAR INJECTION */(function(process) {/**
210 | * Copyright (c) 2013-present, Facebook, Inc.
211 | *
212 | * This source code is licensed under the MIT license found in the
213 | * LICENSE file in the root directory of this source tree.
214 | */
215 |
216 | if (process.env.NODE_ENV !== 'production') {
217 | var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
218 | Symbol.for &&
219 | Symbol.for('react.element')) ||
220 | 0xeac7;
221 |
222 | var isValidElement = function(object) {
223 | return typeof object === 'object' &&
224 | object !== null &&
225 | object.$$typeof === REACT_ELEMENT_TYPE;
226 | };
227 |
228 | // By explicitly using `prop-types` you are opting into new development behavior.
229 | // http://fb.me/prop-types-in-prod
230 | var throwOnDirectAccess = true;
231 | module.exports = __webpack_require__(5)(isValidElement, throwOnDirectAccess);
232 | } else {
233 | // By explicitly using `prop-types` you are opting into new production behavior.
234 | // http://fb.me/prop-types-in-prod
235 | module.exports = __webpack_require__(12)();
236 | }
237 |
238 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
239 |
240 | /***/ }),
241 | /* 4 */
242 | /***/ (function(module, exports) {
243 |
244 | // shim for using process in browser
245 | var process = module.exports = {};
246 |
247 | // cached from whatever global is present so that test runners that stub it
248 | // don't break things. But we need to wrap it in a try catch in case it is
249 | // wrapped in strict mode code which doesn't define any globals. It's inside a
250 | // function because try/catches deoptimize in certain engines.
251 |
252 | var cachedSetTimeout;
253 | var cachedClearTimeout;
254 |
255 | function defaultSetTimout() {
256 | throw new Error('setTimeout has not been defined');
257 | }
258 | function defaultClearTimeout () {
259 | throw new Error('clearTimeout has not been defined');
260 | }
261 | (function () {
262 | try {
263 | if (typeof setTimeout === 'function') {
264 | cachedSetTimeout = setTimeout;
265 | } else {
266 | cachedSetTimeout = defaultSetTimout;
267 | }
268 | } catch (e) {
269 | cachedSetTimeout = defaultSetTimout;
270 | }
271 | try {
272 | if (typeof clearTimeout === 'function') {
273 | cachedClearTimeout = clearTimeout;
274 | } else {
275 | cachedClearTimeout = defaultClearTimeout;
276 | }
277 | } catch (e) {
278 | cachedClearTimeout = defaultClearTimeout;
279 | }
280 | } ())
281 | function runTimeout(fun) {
282 | if (cachedSetTimeout === setTimeout) {
283 | //normal enviroments in sane situations
284 | return setTimeout(fun, 0);
285 | }
286 | // if setTimeout wasn't available but was latter defined
287 | if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
288 | cachedSetTimeout = setTimeout;
289 | return setTimeout(fun, 0);
290 | }
291 | try {
292 | // when when somebody has screwed with setTimeout but no I.E. maddness
293 | return cachedSetTimeout(fun, 0);
294 | } catch(e){
295 | try {
296 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
297 | return cachedSetTimeout.call(null, fun, 0);
298 | } catch(e){
299 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
300 | return cachedSetTimeout.call(this, fun, 0);
301 | }
302 | }
303 |
304 |
305 | }
306 | function runClearTimeout(marker) {
307 | if (cachedClearTimeout === clearTimeout) {
308 | //normal enviroments in sane situations
309 | return clearTimeout(marker);
310 | }
311 | // if clearTimeout wasn't available but was latter defined
312 | if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
313 | cachedClearTimeout = clearTimeout;
314 | return clearTimeout(marker);
315 | }
316 | try {
317 | // when when somebody has screwed with setTimeout but no I.E. maddness
318 | return cachedClearTimeout(marker);
319 | } catch (e){
320 | try {
321 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
322 | return cachedClearTimeout.call(null, marker);
323 | } catch (e){
324 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
325 | // Some versions of I.E. have different rules for clearTimeout vs setTimeout
326 | return cachedClearTimeout.call(this, marker);
327 | }
328 | }
329 |
330 |
331 |
332 | }
333 | var queue = [];
334 | var draining = false;
335 | var currentQueue;
336 | var queueIndex = -1;
337 |
338 | function cleanUpNextTick() {
339 | if (!draining || !currentQueue) {
340 | return;
341 | }
342 | draining = false;
343 | if (currentQueue.length) {
344 | queue = currentQueue.concat(queue);
345 | } else {
346 | queueIndex = -1;
347 | }
348 | if (queue.length) {
349 | drainQueue();
350 | }
351 | }
352 |
353 | function drainQueue() {
354 | if (draining) {
355 | return;
356 | }
357 | var timeout = runTimeout(cleanUpNextTick);
358 | draining = true;
359 |
360 | var len = queue.length;
361 | while(len) {
362 | currentQueue = queue;
363 | queue = [];
364 | while (++queueIndex < len) {
365 | if (currentQueue) {
366 | currentQueue[queueIndex].run();
367 | }
368 | }
369 | queueIndex = -1;
370 | len = queue.length;
371 | }
372 | currentQueue = null;
373 | draining = false;
374 | runClearTimeout(timeout);
375 | }
376 |
377 | process.nextTick = function (fun) {
378 | var args = new Array(arguments.length - 1);
379 | if (arguments.length > 1) {
380 | for (var i = 1; i < arguments.length; i++) {
381 | args[i - 1] = arguments[i];
382 | }
383 | }
384 | queue.push(new Item(fun, args));
385 | if (queue.length === 1 && !draining) {
386 | runTimeout(drainQueue);
387 | }
388 | };
389 |
390 | // v8 likes predictible objects
391 | function Item(fun, array) {
392 | this.fun = fun;
393 | this.array = array;
394 | }
395 | Item.prototype.run = function () {
396 | this.fun.apply(null, this.array);
397 | };
398 | process.title = 'browser';
399 | process.browser = true;
400 | process.env = {};
401 | process.argv = [];
402 | process.version = ''; // empty string to avoid regexp issues
403 | process.versions = {};
404 |
405 | function noop() {}
406 |
407 | process.on = noop;
408 | process.addListener = noop;
409 | process.once = noop;
410 | process.off = noop;
411 | process.removeListener = noop;
412 | process.removeAllListeners = noop;
413 | process.emit = noop;
414 | process.prependListener = noop;
415 | process.prependOnceListener = noop;
416 |
417 | process.listeners = function (name) { return [] }
418 |
419 | process.binding = function (name) {
420 | throw new Error('process.binding is not supported');
421 | };
422 |
423 | process.cwd = function () { return '/' };
424 | process.chdir = function (dir) {
425 | throw new Error('process.chdir is not supported');
426 | };
427 | process.umask = function() { return 0; };
428 |
429 |
430 | /***/ }),
431 | /* 5 */
432 | /***/ (function(module, exports, __webpack_require__) {
433 |
434 | /* WEBPACK VAR INJECTION */(function(process) {/**
435 | * Copyright (c) 2013-present, Facebook, Inc.
436 | *
437 | * This source code is licensed under the MIT license found in the
438 | * LICENSE file in the root directory of this source tree.
439 | */
440 |
441 | 'use strict';
442 |
443 | var emptyFunction = __webpack_require__(6);
444 | var invariant = __webpack_require__(7);
445 | var warning = __webpack_require__(8);
446 | var assign = __webpack_require__(9);
447 |
448 | var ReactPropTypesSecret = __webpack_require__(10);
449 | var checkPropTypes = __webpack_require__(11);
450 |
451 | module.exports = function(isValidElement, throwOnDirectAccess) {
452 | /* global Symbol */
453 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
454 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
455 |
456 | /**
457 | * Returns the iterator method function contained on the iterable object.
458 | *
459 | * Be sure to invoke the function with the iterable as context:
460 | *
461 | * var iteratorFn = getIteratorFn(myIterable);
462 | * if (iteratorFn) {
463 | * var iterator = iteratorFn.call(myIterable);
464 | * ...
465 | * }
466 | *
467 | * @param {?object} maybeIterable
468 | * @return {?function}
469 | */
470 | function getIteratorFn(maybeIterable) {
471 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
472 | if (typeof iteratorFn === 'function') {
473 | return iteratorFn;
474 | }
475 | }
476 |
477 | /**
478 | * Collection of methods that allow declaration and validation of props that are
479 | * supplied to React components. Example usage:
480 | *
481 | * var Props = require('ReactPropTypes');
482 | * var MyArticle = React.createClass({
483 | * propTypes: {
484 | * // An optional string prop named "description".
485 | * description: Props.string,
486 | *
487 | * // A required enum prop named "category".
488 | * category: Props.oneOf(['News','Photos']).isRequired,
489 | *
490 | * // A prop named "dialog" that requires an instance of Dialog.
491 | * dialog: Props.instanceOf(Dialog).isRequired
492 | * },
493 | * render: function() { ... }
494 | * });
495 | *
496 | * A more formal specification of how these methods are used:
497 | *
498 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
499 | * decl := ReactPropTypes.{type}(.isRequired)?
500 | *
501 | * Each and every declaration produces a function with the same signature. This
502 | * allows the creation of custom validation functions. For example:
503 | *
504 | * var MyLink = React.createClass({
505 | * propTypes: {
506 | * // An optional string or URI prop named "href".
507 | * href: function(props, propName, componentName) {
508 | * var propValue = props[propName];
509 | * if (propValue != null && typeof propValue !== 'string' &&
510 | * !(propValue instanceof URI)) {
511 | * return new Error(
512 | * 'Expected a string or an URI for ' + propName + ' in ' +
513 | * componentName
514 | * );
515 | * }
516 | * }
517 | * },
518 | * render: function() {...}
519 | * });
520 | *
521 | * @internal
522 | */
523 |
524 | var ANONYMOUS = '<>';
525 |
526 | // Important!
527 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
528 | var ReactPropTypes = {
529 | array: createPrimitiveTypeChecker('array'),
530 | bool: createPrimitiveTypeChecker('boolean'),
531 | func: createPrimitiveTypeChecker('function'),
532 | number: createPrimitiveTypeChecker('number'),
533 | object: createPrimitiveTypeChecker('object'),
534 | string: createPrimitiveTypeChecker('string'),
535 | symbol: createPrimitiveTypeChecker('symbol'),
536 |
537 | any: createAnyTypeChecker(),
538 | arrayOf: createArrayOfTypeChecker,
539 | element: createElementTypeChecker(),
540 | instanceOf: createInstanceTypeChecker,
541 | node: createNodeChecker(),
542 | objectOf: createObjectOfTypeChecker,
543 | oneOf: createEnumTypeChecker,
544 | oneOfType: createUnionTypeChecker,
545 | shape: createShapeTypeChecker,
546 | exact: createStrictShapeTypeChecker,
547 | };
548 |
549 | /**
550 | * inlined Object.is polyfill to avoid requiring consumers ship their own
551 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
552 | */
553 | /*eslint-disable no-self-compare*/
554 | function is(x, y) {
555 | // SameValue algorithm
556 | if (x === y) {
557 | // Steps 1-5, 7-10
558 | // Steps 6.b-6.e: +0 != -0
559 | return x !== 0 || 1 / x === 1 / y;
560 | } else {
561 | // Step 6.a: NaN == NaN
562 | return x !== x && y !== y;
563 | }
564 | }
565 | /*eslint-enable no-self-compare*/
566 |
567 | /**
568 | * We use an Error-like object for backward compatibility as people may call
569 | * PropTypes directly and inspect their output. However, we don't use real
570 | * Errors anymore. We don't inspect their stack anyway, and creating them
571 | * is prohibitively expensive if they are created too often, such as what
572 | * happens in oneOfType() for any type before the one that matched.
573 | */
574 | function PropTypeError(message) {
575 | this.message = message;
576 | this.stack = '';
577 | }
578 | // Make `instanceof Error` still work for returned errors.
579 | PropTypeError.prototype = Error.prototype;
580 |
581 | function createChainableTypeChecker(validate) {
582 | if (process.env.NODE_ENV !== 'production') {
583 | var manualPropTypeCallCache = {};
584 | var manualPropTypeWarningCount = 0;
585 | }
586 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
587 | componentName = componentName || ANONYMOUS;
588 | propFullName = propFullName || propName;
589 |
590 | if (secret !== ReactPropTypesSecret) {
591 | if (throwOnDirectAccess) {
592 | // New behavior only for users of `prop-types` package
593 | invariant(
594 | false,
595 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
596 | 'Use `PropTypes.checkPropTypes()` to call them. ' +
597 | 'Read more at http://fb.me/use-check-prop-types'
598 | );
599 | } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') {
600 | // Old behavior for people using React.PropTypes
601 | var cacheKey = componentName + ':' + propName;
602 | if (
603 | !manualPropTypeCallCache[cacheKey] &&
604 | // Avoid spamming the console because they are often not actionable except for lib authors
605 | manualPropTypeWarningCount < 3
606 | ) {
607 | warning(
608 | false,
609 | 'You are manually calling a React.PropTypes validation ' +
610 | 'function for the `%s` prop on `%s`. This is deprecated ' +
611 | 'and will throw in the standalone `prop-types` package. ' +
612 | 'You may be seeing this warning due to a third-party PropTypes ' +
613 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.',
614 | propFullName,
615 | componentName
616 | );
617 | manualPropTypeCallCache[cacheKey] = true;
618 | manualPropTypeWarningCount++;
619 | }
620 | }
621 | }
622 | if (props[propName] == null) {
623 | if (isRequired) {
624 | if (props[propName] === null) {
625 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
626 | }
627 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
628 | }
629 | return null;
630 | } else {
631 | return validate(props, propName, componentName, location, propFullName);
632 | }
633 | }
634 |
635 | var chainedCheckType = checkType.bind(null, false);
636 | chainedCheckType.isRequired = checkType.bind(null, true);
637 |
638 | return chainedCheckType;
639 | }
640 |
641 | function createPrimitiveTypeChecker(expectedType) {
642 | function validate(props, propName, componentName, location, propFullName, secret) {
643 | var propValue = props[propName];
644 | var propType = getPropType(propValue);
645 | if (propType !== expectedType) {
646 | // `propValue` being instance of, say, date/regexp, pass the 'object'
647 | // check, but we can offer a more precise error message here rather than
648 | // 'of type `object`'.
649 | var preciseType = getPreciseType(propValue);
650 |
651 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
652 | }
653 | return null;
654 | }
655 | return createChainableTypeChecker(validate);
656 | }
657 |
658 | function createAnyTypeChecker() {
659 | return createChainableTypeChecker(emptyFunction.thatReturnsNull);
660 | }
661 |
662 | function createArrayOfTypeChecker(typeChecker) {
663 | function validate(props, propName, componentName, location, propFullName) {
664 | if (typeof typeChecker !== 'function') {
665 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
666 | }
667 | var propValue = props[propName];
668 | if (!Array.isArray(propValue)) {
669 | var propType = getPropType(propValue);
670 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
671 | }
672 | for (var i = 0; i < propValue.length; i++) {
673 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
674 | if (error instanceof Error) {
675 | return error;
676 | }
677 | }
678 | return null;
679 | }
680 | return createChainableTypeChecker(validate);
681 | }
682 |
683 | function createElementTypeChecker() {
684 | function validate(props, propName, componentName, location, propFullName) {
685 | var propValue = props[propName];
686 | if (!isValidElement(propValue)) {
687 | var propType = getPropType(propValue);
688 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
689 | }
690 | return null;
691 | }
692 | return createChainableTypeChecker(validate);
693 | }
694 |
695 | function createInstanceTypeChecker(expectedClass) {
696 | function validate(props, propName, componentName, location, propFullName) {
697 | if (!(props[propName] instanceof expectedClass)) {
698 | var expectedClassName = expectedClass.name || ANONYMOUS;
699 | var actualClassName = getClassName(props[propName]);
700 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
701 | }
702 | return null;
703 | }
704 | return createChainableTypeChecker(validate);
705 | }
706 |
707 | function createEnumTypeChecker(expectedValues) {
708 | if (!Array.isArray(expectedValues)) {
709 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
710 | return emptyFunction.thatReturnsNull;
711 | }
712 |
713 | function validate(props, propName, componentName, location, propFullName) {
714 | var propValue = props[propName];
715 | for (var i = 0; i < expectedValues.length; i++) {
716 | if (is(propValue, expectedValues[i])) {
717 | return null;
718 | }
719 | }
720 |
721 | var valuesString = JSON.stringify(expectedValues);
722 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
723 | }
724 | return createChainableTypeChecker(validate);
725 | }
726 |
727 | function createObjectOfTypeChecker(typeChecker) {
728 | function validate(props, propName, componentName, location, propFullName) {
729 | if (typeof typeChecker !== 'function') {
730 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
731 | }
732 | var propValue = props[propName];
733 | var propType = getPropType(propValue);
734 | if (propType !== 'object') {
735 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
736 | }
737 | for (var key in propValue) {
738 | if (propValue.hasOwnProperty(key)) {
739 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
740 | if (error instanceof Error) {
741 | return error;
742 | }
743 | }
744 | }
745 | return null;
746 | }
747 | return createChainableTypeChecker(validate);
748 | }
749 |
750 | function createUnionTypeChecker(arrayOfTypeCheckers) {
751 | if (!Array.isArray(arrayOfTypeCheckers)) {
752 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
753 | return emptyFunction.thatReturnsNull;
754 | }
755 |
756 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
757 | var checker = arrayOfTypeCheckers[i];
758 | if (typeof checker !== 'function') {
759 | warning(
760 | false,
761 | 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
762 | 'received %s at index %s.',
763 | getPostfixForTypeWarning(checker),
764 | i
765 | );
766 | return emptyFunction.thatReturnsNull;
767 | }
768 | }
769 |
770 | function validate(props, propName, componentName, location, propFullName) {
771 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
772 | var checker = arrayOfTypeCheckers[i];
773 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
774 | return null;
775 | }
776 | }
777 |
778 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
779 | }
780 | return createChainableTypeChecker(validate);
781 | }
782 |
783 | function createNodeChecker() {
784 | function validate(props, propName, componentName, location, propFullName) {
785 | if (!isNode(props[propName])) {
786 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
787 | }
788 | return null;
789 | }
790 | return createChainableTypeChecker(validate);
791 | }
792 |
793 | function createShapeTypeChecker(shapeTypes) {
794 | function validate(props, propName, componentName, location, propFullName) {
795 | var propValue = props[propName];
796 | var propType = getPropType(propValue);
797 | if (propType !== 'object') {
798 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
799 | }
800 | for (var key in shapeTypes) {
801 | var checker = shapeTypes[key];
802 | if (!checker) {
803 | continue;
804 | }
805 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
806 | if (error) {
807 | return error;
808 | }
809 | }
810 | return null;
811 | }
812 | return createChainableTypeChecker(validate);
813 | }
814 |
815 | function createStrictShapeTypeChecker(shapeTypes) {
816 | function validate(props, propName, componentName, location, propFullName) {
817 | var propValue = props[propName];
818 | var propType = getPropType(propValue);
819 | if (propType !== 'object') {
820 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
821 | }
822 | // We need to check all keys in case some are required but missing from
823 | // props.
824 | var allKeys = assign({}, props[propName], shapeTypes);
825 | for (var key in allKeys) {
826 | var checker = shapeTypes[key];
827 | if (!checker) {
828 | return new PropTypeError(
829 | 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
830 | '\nBad object: ' + JSON.stringify(props[propName], null, ' ') +
831 | '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ')
832 | );
833 | }
834 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
835 | if (error) {
836 | return error;
837 | }
838 | }
839 | return null;
840 | }
841 |
842 | return createChainableTypeChecker(validate);
843 | }
844 |
845 | function isNode(propValue) {
846 | switch (typeof propValue) {
847 | case 'number':
848 | case 'string':
849 | case 'undefined':
850 | return true;
851 | case 'boolean':
852 | return !propValue;
853 | case 'object':
854 | if (Array.isArray(propValue)) {
855 | return propValue.every(isNode);
856 | }
857 | if (propValue === null || isValidElement(propValue)) {
858 | return true;
859 | }
860 |
861 | var iteratorFn = getIteratorFn(propValue);
862 | if (iteratorFn) {
863 | var iterator = iteratorFn.call(propValue);
864 | var step;
865 | if (iteratorFn !== propValue.entries) {
866 | while (!(step = iterator.next()).done) {
867 | if (!isNode(step.value)) {
868 | return false;
869 | }
870 | }
871 | } else {
872 | // Iterator will provide entry [k,v] tuples rather than values.
873 | while (!(step = iterator.next()).done) {
874 | var entry = step.value;
875 | if (entry) {
876 | if (!isNode(entry[1])) {
877 | return false;
878 | }
879 | }
880 | }
881 | }
882 | } else {
883 | return false;
884 | }
885 |
886 | return true;
887 | default:
888 | return false;
889 | }
890 | }
891 |
892 | function isSymbol(propType, propValue) {
893 | // Native Symbol.
894 | if (propType === 'symbol') {
895 | return true;
896 | }
897 |
898 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
899 | if (propValue['@@toStringTag'] === 'Symbol') {
900 | return true;
901 | }
902 |
903 | // Fallback for non-spec compliant Symbols which are polyfilled.
904 | if (typeof Symbol === 'function' && propValue instanceof Symbol) {
905 | return true;
906 | }
907 |
908 | return false;
909 | }
910 |
911 | // Equivalent of `typeof` but with special handling for array and regexp.
912 | function getPropType(propValue) {
913 | var propType = typeof propValue;
914 | if (Array.isArray(propValue)) {
915 | return 'array';
916 | }
917 | if (propValue instanceof RegExp) {
918 | // Old webkits (at least until Android 4.0) return 'function' rather than
919 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
920 | // passes PropTypes.object.
921 | return 'object';
922 | }
923 | if (isSymbol(propType, propValue)) {
924 | return 'symbol';
925 | }
926 | return propType;
927 | }
928 |
929 | // This handles more types than `getPropType`. Only used for error messages.
930 | // See `createPrimitiveTypeChecker`.
931 | function getPreciseType(propValue) {
932 | if (typeof propValue === 'undefined' || propValue === null) {
933 | return '' + propValue;
934 | }
935 | var propType = getPropType(propValue);
936 | if (propType === 'object') {
937 | if (propValue instanceof Date) {
938 | return 'date';
939 | } else if (propValue instanceof RegExp) {
940 | return 'regexp';
941 | }
942 | }
943 | return propType;
944 | }
945 |
946 | // Returns a string that is postfixed to a warning about an invalid type.
947 | // For example, "undefined" or "of type array"
948 | function getPostfixForTypeWarning(value) {
949 | var type = getPreciseType(value);
950 | switch (type) {
951 | case 'array':
952 | case 'object':
953 | return 'an ' + type;
954 | case 'boolean':
955 | case 'date':
956 | case 'regexp':
957 | return 'a ' + type;
958 | default:
959 | return type;
960 | }
961 | }
962 |
963 | // Returns class name of the object, if any.
964 | function getClassName(propValue) {
965 | if (!propValue.constructor || !propValue.constructor.name) {
966 | return ANONYMOUS;
967 | }
968 | return propValue.constructor.name;
969 | }
970 |
971 | ReactPropTypes.checkPropTypes = checkPropTypes;
972 | ReactPropTypes.PropTypes = ReactPropTypes;
973 |
974 | return ReactPropTypes;
975 | };
976 |
977 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
978 |
979 | /***/ }),
980 | /* 6 */
981 | /***/ (function(module, exports) {
982 |
983 | "use strict";
984 |
985 | /**
986 | * Copyright (c) 2013-present, Facebook, Inc.
987 | *
988 | * This source code is licensed under the MIT license found in the
989 | * LICENSE file in the root directory of this source tree.
990 | *
991 | *
992 | */
993 |
994 | function makeEmptyFunction(arg) {
995 | return function () {
996 | return arg;
997 | };
998 | }
999 |
1000 | /**
1001 | * This function accepts and discards inputs; it has no side effects. This is
1002 | * primarily useful idiomatically for overridable function endpoints which
1003 | * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
1004 | */
1005 | var emptyFunction = function emptyFunction() {};
1006 |
1007 | emptyFunction.thatReturns = makeEmptyFunction;
1008 | emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
1009 | emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
1010 | emptyFunction.thatReturnsNull = makeEmptyFunction(null);
1011 | emptyFunction.thatReturnsThis = function () {
1012 | return this;
1013 | };
1014 | emptyFunction.thatReturnsArgument = function (arg) {
1015 | return arg;
1016 | };
1017 |
1018 | module.exports = emptyFunction;
1019 |
1020 | /***/ }),
1021 | /* 7 */
1022 | /***/ (function(module, exports, __webpack_require__) {
1023 |
1024 | /* WEBPACK VAR INJECTION */(function(process) {/**
1025 | * Copyright (c) 2013-present, Facebook, Inc.
1026 | *
1027 | * This source code is licensed under the MIT license found in the
1028 | * LICENSE file in the root directory of this source tree.
1029 | *
1030 | */
1031 |
1032 | 'use strict';
1033 |
1034 | /**
1035 | * Use invariant() to assert state which your program assumes to be true.
1036 | *
1037 | * Provide sprintf-style format (only %s is supported) and arguments
1038 | * to provide information about what broke and what you were
1039 | * expecting.
1040 | *
1041 | * The invariant message will be stripped in production, but the invariant
1042 | * will remain to ensure logic does not differ in production.
1043 | */
1044 |
1045 | var validateFormat = function validateFormat(format) {};
1046 |
1047 | if (process.env.NODE_ENV !== 'production') {
1048 | validateFormat = function validateFormat(format) {
1049 | if (format === undefined) {
1050 | throw new Error('invariant requires an error message argument');
1051 | }
1052 | };
1053 | }
1054 |
1055 | function invariant(condition, format, a, b, c, d, e, f) {
1056 | validateFormat(format);
1057 |
1058 | if (!condition) {
1059 | var error;
1060 | if (format === undefined) {
1061 | error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
1062 | } else {
1063 | var args = [a, b, c, d, e, f];
1064 | var argIndex = 0;
1065 | error = new Error(format.replace(/%s/g, function () {
1066 | return args[argIndex++];
1067 | }));
1068 | error.name = 'Invariant Violation';
1069 | }
1070 |
1071 | error.framesToPop = 1; // we don't care about invariant's own frame
1072 | throw error;
1073 | }
1074 | }
1075 |
1076 | module.exports = invariant;
1077 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
1078 |
1079 | /***/ }),
1080 | /* 8 */
1081 | /***/ (function(module, exports, __webpack_require__) {
1082 |
1083 | /* WEBPACK VAR INJECTION */(function(process) {/**
1084 | * Copyright (c) 2014-present, Facebook, Inc.
1085 | *
1086 | * This source code is licensed under the MIT license found in the
1087 | * LICENSE file in the root directory of this source tree.
1088 | *
1089 | */
1090 |
1091 | 'use strict';
1092 |
1093 | var emptyFunction = __webpack_require__(6);
1094 |
1095 | /**
1096 | * Similar to invariant but only logs a warning if the condition is not met.
1097 | * This can be used to log issues in development environments in critical
1098 | * paths. Removing the logging code for production environments will keep the
1099 | * same logic and follow the same code paths.
1100 | */
1101 |
1102 | var warning = emptyFunction;
1103 |
1104 | if (process.env.NODE_ENV !== 'production') {
1105 | var printWarning = function printWarning(format) {
1106 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1107 | args[_key - 1] = arguments[_key];
1108 | }
1109 |
1110 | var argIndex = 0;
1111 | var message = 'Warning: ' + format.replace(/%s/g, function () {
1112 | return args[argIndex++];
1113 | });
1114 | if (typeof console !== 'undefined') {
1115 | console.error(message);
1116 | }
1117 | try {
1118 | // --- Welcome to debugging React ---
1119 | // This error was thrown as a convenience so that you can use this stack
1120 | // to find the callsite that caused this warning to fire.
1121 | throw new Error(message);
1122 | } catch (x) {}
1123 | };
1124 |
1125 | warning = function warning(condition, format) {
1126 | if (format === undefined) {
1127 | throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
1128 | }
1129 |
1130 | if (format.indexOf('Failed Composite propType: ') === 0) {
1131 | return; // Ignore CompositeComponent proptype check.
1132 | }
1133 |
1134 | if (!condition) {
1135 | for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
1136 | args[_key2 - 2] = arguments[_key2];
1137 | }
1138 |
1139 | printWarning.apply(undefined, [format].concat(args));
1140 | }
1141 | };
1142 | }
1143 |
1144 | module.exports = warning;
1145 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
1146 |
1147 | /***/ }),
1148 | /* 9 */
1149 | /***/ (function(module, exports) {
1150 |
1151 | /*
1152 | object-assign
1153 | (c) Sindre Sorhus
1154 | @license MIT
1155 | */
1156 |
1157 | 'use strict';
1158 | /* eslint-disable no-unused-vars */
1159 | var getOwnPropertySymbols = Object.getOwnPropertySymbols;
1160 | var hasOwnProperty = Object.prototype.hasOwnProperty;
1161 | var propIsEnumerable = Object.prototype.propertyIsEnumerable;
1162 |
1163 | function toObject(val) {
1164 | if (val === null || val === undefined) {
1165 | throw new TypeError('Object.assign cannot be called with null or undefined');
1166 | }
1167 |
1168 | return Object(val);
1169 | }
1170 |
1171 | function shouldUseNative() {
1172 | try {
1173 | if (!Object.assign) {
1174 | return false;
1175 | }
1176 |
1177 | // Detect buggy property enumeration order in older V8 versions.
1178 |
1179 | // https://bugs.chromium.org/p/v8/issues/detail?id=4118
1180 | var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
1181 | test1[5] = 'de';
1182 | if (Object.getOwnPropertyNames(test1)[0] === '5') {
1183 | return false;
1184 | }
1185 |
1186 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
1187 | var test2 = {};
1188 | for (var i = 0; i < 10; i++) {
1189 | test2['_' + String.fromCharCode(i)] = i;
1190 | }
1191 | var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
1192 | return test2[n];
1193 | });
1194 | if (order2.join('') !== '0123456789') {
1195 | return false;
1196 | }
1197 |
1198 | // https://bugs.chromium.org/p/v8/issues/detail?id=3056
1199 | var test3 = {};
1200 | 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
1201 | test3[letter] = letter;
1202 | });
1203 | if (Object.keys(Object.assign({}, test3)).join('') !==
1204 | 'abcdefghijklmnopqrst') {
1205 | return false;
1206 | }
1207 |
1208 | return true;
1209 | } catch (err) {
1210 | // We don't expect any of the above to throw, but better to be safe.
1211 | return false;
1212 | }
1213 | }
1214 |
1215 | module.exports = shouldUseNative() ? Object.assign : function (target, source) {
1216 | var from;
1217 | var to = toObject(target);
1218 | var symbols;
1219 |
1220 | for (var s = 1; s < arguments.length; s++) {
1221 | from = Object(arguments[s]);
1222 |
1223 | for (var key in from) {
1224 | if (hasOwnProperty.call(from, key)) {
1225 | to[key] = from[key];
1226 | }
1227 | }
1228 |
1229 | if (getOwnPropertySymbols) {
1230 | symbols = getOwnPropertySymbols(from);
1231 | for (var i = 0; i < symbols.length; i++) {
1232 | if (propIsEnumerable.call(from, symbols[i])) {
1233 | to[symbols[i]] = from[symbols[i]];
1234 | }
1235 | }
1236 | }
1237 | }
1238 |
1239 | return to;
1240 | };
1241 |
1242 |
1243 | /***/ }),
1244 | /* 10 */
1245 | /***/ (function(module, exports) {
1246 |
1247 | /**
1248 | * Copyright (c) 2013-present, Facebook, Inc.
1249 | *
1250 | * This source code is licensed under the MIT license found in the
1251 | * LICENSE file in the root directory of this source tree.
1252 | */
1253 |
1254 | 'use strict';
1255 |
1256 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
1257 |
1258 | module.exports = ReactPropTypesSecret;
1259 |
1260 |
1261 | /***/ }),
1262 | /* 11 */
1263 | /***/ (function(module, exports, __webpack_require__) {
1264 |
1265 | /* WEBPACK VAR INJECTION */(function(process) {/**
1266 | * Copyright (c) 2013-present, Facebook, Inc.
1267 | *
1268 | * This source code is licensed under the MIT license found in the
1269 | * LICENSE file in the root directory of this source tree.
1270 | */
1271 |
1272 | 'use strict';
1273 |
1274 | if (process.env.NODE_ENV !== 'production') {
1275 | var invariant = __webpack_require__(7);
1276 | var warning = __webpack_require__(8);
1277 | var ReactPropTypesSecret = __webpack_require__(10);
1278 | var loggedTypeFailures = {};
1279 | }
1280 |
1281 | /**
1282 | * Assert that the values match with the type specs.
1283 | * Error messages are memorized and will only be shown once.
1284 | *
1285 | * @param {object} typeSpecs Map of name to a ReactPropType
1286 | * @param {object} values Runtime values that need to be type-checked
1287 | * @param {string} location e.g. "prop", "context", "child context"
1288 | * @param {string} componentName Name of the component for error messages.
1289 | * @param {?Function} getStack Returns the component stack.
1290 | * @private
1291 | */
1292 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
1293 | if (process.env.NODE_ENV !== 'production') {
1294 | for (var typeSpecName in typeSpecs) {
1295 | if (typeSpecs.hasOwnProperty(typeSpecName)) {
1296 | var error;
1297 | // Prop type validation may throw. In case they do, we don't want to
1298 | // fail the render phase where it didn't fail before. So we log it.
1299 | // After these have been cleaned up, we'll let them throw.
1300 | try {
1301 | // This is intentionally an invariant that gets caught. It's the same
1302 | // behavior as without this statement except with a better message.
1303 | invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]);
1304 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
1305 | } catch (ex) {
1306 | error = ex;
1307 | }
1308 | warning(!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);
1309 | if (error instanceof Error && !(error.message in loggedTypeFailures)) {
1310 | // Only monitor this failure once because there tends to be a lot of the
1311 | // same error.
1312 | loggedTypeFailures[error.message] = true;
1313 |
1314 | var stack = getStack ? getStack() : '';
1315 |
1316 | warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
1317 | }
1318 | }
1319 | }
1320 | }
1321 | }
1322 |
1323 | module.exports = checkPropTypes;
1324 |
1325 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
1326 |
1327 | /***/ }),
1328 | /* 12 */
1329 | /***/ (function(module, exports, __webpack_require__) {
1330 |
1331 | /**
1332 | * Copyright (c) 2013-present, Facebook, Inc.
1333 | *
1334 | * This source code is licensed under the MIT license found in the
1335 | * LICENSE file in the root directory of this source tree.
1336 | */
1337 |
1338 | 'use strict';
1339 |
1340 | var emptyFunction = __webpack_require__(6);
1341 | var invariant = __webpack_require__(7);
1342 | var ReactPropTypesSecret = __webpack_require__(10);
1343 |
1344 | module.exports = function() {
1345 | function shim(props, propName, componentName, location, propFullName, secret) {
1346 | if (secret === ReactPropTypesSecret) {
1347 | // It is still safe when called from React.
1348 | return;
1349 | }
1350 | invariant(
1351 | false,
1352 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
1353 | 'Use PropTypes.checkPropTypes() to call them. ' +
1354 | 'Read more at http://fb.me/use-check-prop-types'
1355 | );
1356 | };
1357 | shim.isRequired = shim;
1358 | function getShim() {
1359 | return shim;
1360 | };
1361 | // Important!
1362 | // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
1363 | var ReactPropTypes = {
1364 | array: shim,
1365 | bool: shim,
1366 | func: shim,
1367 | number: shim,
1368 | object: shim,
1369 | string: shim,
1370 | symbol: shim,
1371 |
1372 | any: shim,
1373 | arrayOf: getShim,
1374 | element: shim,
1375 | instanceOf: getShim,
1376 | node: shim,
1377 | objectOf: getShim,
1378 | oneOf: getShim,
1379 | oneOfType: getShim,
1380 | shape: getShim,
1381 | exact: getShim
1382 | };
1383 |
1384 | ReactPropTypes.checkPropTypes = emptyFunction;
1385 | ReactPropTypes.PropTypes = ReactPropTypes;
1386 |
1387 | return ReactPropTypes;
1388 | };
1389 |
1390 |
1391 | /***/ }),
1392 | /* 13 */
1393 | /***/ (function(module, exports, __webpack_require__) {
1394 |
1395 | /**
1396 | * Copyright (c) 2013-present, Facebook, Inc.
1397 | *
1398 | * This source code is licensed under the MIT license found in the
1399 | * LICENSE file in the root directory of this source tree.
1400 | *
1401 | */
1402 |
1403 | 'use strict';
1404 |
1405 | var React = __webpack_require__(2);
1406 | var factory = __webpack_require__(14);
1407 |
1408 | if (typeof React === 'undefined') {
1409 | throw Error(
1410 | 'create-react-class could not find the React object. If you are using script tags, ' +
1411 | 'make sure that React is being loaded before create-react-class.'
1412 | );
1413 | }
1414 |
1415 | // Hack to grab NoopUpdateQueue from isomorphic React
1416 | var ReactNoopUpdateQueue = new React.Component().updater;
1417 |
1418 | module.exports = factory(
1419 | React.Component,
1420 | React.isValidElement,
1421 | ReactNoopUpdateQueue
1422 | );
1423 |
1424 |
1425 | /***/ }),
1426 | /* 14 */
1427 | /***/ (function(module, exports, __webpack_require__) {
1428 |
1429 | /* WEBPACK VAR INJECTION */(function(process) {/**
1430 | * Copyright (c) 2013-present, Facebook, Inc.
1431 | *
1432 | * This source code is licensed under the MIT license found in the
1433 | * LICENSE file in the root directory of this source tree.
1434 | *
1435 | */
1436 |
1437 | 'use strict';
1438 |
1439 | var _assign = __webpack_require__(9);
1440 |
1441 | var emptyObject = __webpack_require__(15);
1442 | var _invariant = __webpack_require__(7);
1443 |
1444 | if (process.env.NODE_ENV !== 'production') {
1445 | var warning = __webpack_require__(8);
1446 | }
1447 |
1448 | var MIXINS_KEY = 'mixins';
1449 |
1450 | // Helper function to allow the creation of anonymous functions which do not
1451 | // have .name set to the name of the variable being assigned to.
1452 | function identity(fn) {
1453 | return fn;
1454 | }
1455 |
1456 | var ReactPropTypeLocationNames;
1457 | if (process.env.NODE_ENV !== 'production') {
1458 | ReactPropTypeLocationNames = {
1459 | prop: 'prop',
1460 | context: 'context',
1461 | childContext: 'child context'
1462 | };
1463 | } else {
1464 | ReactPropTypeLocationNames = {};
1465 | }
1466 |
1467 | function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
1468 | /**
1469 | * Policies that describe methods in `ReactClassInterface`.
1470 | */
1471 |
1472 | var injectedMixins = [];
1473 |
1474 | /**
1475 | * Composite components are higher-level components that compose other composite
1476 | * or host components.
1477 | *
1478 | * To create a new type of `ReactClass`, pass a specification of
1479 | * your new class to `React.createClass`. The only requirement of your class
1480 | * specification is that you implement a `render` method.
1481 | *
1482 | * var MyComponent = React.createClass({
1483 | * render: function() {
1484 | * return
Hello World
;
1485 | * }
1486 | * });
1487 | *
1488 | * The class specification supports a specific protocol of methods that have
1489 | * special meaning (e.g. `render`). See `ReactClassInterface` for
1490 | * more the comprehensive protocol. Any other properties and methods in the
1491 | * class specification will be available on the prototype.
1492 | *
1493 | * @interface ReactClassInterface
1494 | * @internal
1495 | */
1496 | var ReactClassInterface = {
1497 | /**
1498 | * An array of Mixin objects to include when defining your component.
1499 | *
1500 | * @type {array}
1501 | * @optional
1502 | */
1503 | mixins: 'DEFINE_MANY',
1504 |
1505 | /**
1506 | * An object containing properties and methods that should be defined on
1507 | * the component's constructor instead of its prototype (static methods).
1508 | *
1509 | * @type {object}
1510 | * @optional
1511 | */
1512 | statics: 'DEFINE_MANY',
1513 |
1514 | /**
1515 | * Definition of prop types for this component.
1516 | *
1517 | * @type {object}
1518 | * @optional
1519 | */
1520 | propTypes: 'DEFINE_MANY',
1521 |
1522 | /**
1523 | * Definition of context types for this component.
1524 | *
1525 | * @type {object}
1526 | * @optional
1527 | */
1528 | contextTypes: 'DEFINE_MANY',
1529 |
1530 | /**
1531 | * Definition of context types this component sets for its children.
1532 | *
1533 | * @type {object}
1534 | * @optional
1535 | */
1536 | childContextTypes: 'DEFINE_MANY',
1537 |
1538 | // ==== Definition methods ====
1539 |
1540 | /**
1541 | * Invoked when the component is mounted. Values in the mapping will be set on
1542 | * `this.props` if that prop is not specified (i.e. using an `in` check).
1543 | *
1544 | * This method is invoked before `getInitialState` and therefore cannot rely
1545 | * on `this.state` or use `this.setState`.
1546 | *
1547 | * @return {object}
1548 | * @optional
1549 | */
1550 | getDefaultProps: 'DEFINE_MANY_MERGED',
1551 |
1552 | /**
1553 | * Invoked once before the component is mounted. The return value will be used
1554 | * as the initial value of `this.state`.
1555 | *
1556 | * getInitialState: function() {
1557 | * return {
1558 | * isOn: false,
1559 | * fooBaz: new BazFoo()
1560 | * }
1561 | * }
1562 | *
1563 | * @return {object}
1564 | * @optional
1565 | */
1566 | getInitialState: 'DEFINE_MANY_MERGED',
1567 |
1568 | /**
1569 | * @return {object}
1570 | * @optional
1571 | */
1572 | getChildContext: 'DEFINE_MANY_MERGED',
1573 |
1574 | /**
1575 | * Uses props from `this.props` and state from `this.state` to render the
1576 | * structure of the component.
1577 | *
1578 | * No guarantees are made about when or how often this method is invoked, so
1579 | * it must not have side effects.
1580 | *
1581 | * render: function() {
1582 | * var name = this.props.name;
1583 | * return
Hello, {name}!
;
1584 | * }
1585 | *
1586 | * @return {ReactComponent}
1587 | * @required
1588 | */
1589 | render: 'DEFINE_ONCE',
1590 |
1591 | // ==== Delegate methods ====
1592 |
1593 | /**
1594 | * Invoked when the component is initially created and about to be mounted.
1595 | * This may have side effects, but any external subscriptions or data created
1596 | * by this method must be cleaned up in `componentWillUnmount`.
1597 | *
1598 | * @optional
1599 | */
1600 | componentWillMount: 'DEFINE_MANY',
1601 |
1602 | /**
1603 | * Invoked when the component has been mounted and has a DOM representation.
1604 | * However, there is no guarantee that the DOM node is in the document.
1605 | *
1606 | * Use this as an opportunity to operate on the DOM when the component has
1607 | * been mounted (initialized and rendered) for the first time.
1608 | *
1609 | * @param {DOMElement} rootNode DOM element representing the component.
1610 | * @optional
1611 | */
1612 | componentDidMount: 'DEFINE_MANY',
1613 |
1614 | /**
1615 | * Invoked before the component receives new props.
1616 | *
1617 | * Use this as an opportunity to react to a prop transition by updating the
1618 | * state using `this.setState`. Current props are accessed via `this.props`.
1619 | *
1620 | * componentWillReceiveProps: function(nextProps, nextContext) {
1621 | * this.setState({
1622 | * likesIncreasing: nextProps.likeCount > this.props.likeCount
1623 | * });
1624 | * }
1625 | *
1626 | * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
1627 | * transition may cause a state change, but the opposite is not true. If you
1628 | * need it, you are probably looking for `componentWillUpdate`.
1629 | *
1630 | * @param {object} nextProps
1631 | * @optional
1632 | */
1633 | componentWillReceiveProps: 'DEFINE_MANY',
1634 |
1635 | /**
1636 | * Invoked while deciding if the component should be updated as a result of
1637 | * receiving new props, state and/or context.
1638 | *
1639 | * Use this as an opportunity to `return false` when you're certain that the
1640 | * transition to the new props/state/context will not require a component
1641 | * update.
1642 | *
1643 | * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
1644 | * return !equal(nextProps, this.props) ||
1645 | * !equal(nextState, this.state) ||
1646 | * !equal(nextContext, this.context);
1647 | * }
1648 | *
1649 | * @param {object} nextProps
1650 | * @param {?object} nextState
1651 | * @param {?object} nextContext
1652 | * @return {boolean} True if the component should update.
1653 | * @optional
1654 | */
1655 | shouldComponentUpdate: 'DEFINE_ONCE',
1656 |
1657 | /**
1658 | * Invoked when the component is about to update due to a transition from
1659 | * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
1660 | * and `nextContext`.
1661 | *
1662 | * Use this as an opportunity to perform preparation before an update occurs.
1663 | *
1664 | * NOTE: You **cannot** use `this.setState()` in this method.
1665 | *
1666 | * @param {object} nextProps
1667 | * @param {?object} nextState
1668 | * @param {?object} nextContext
1669 | * @param {ReactReconcileTransaction} transaction
1670 | * @optional
1671 | */
1672 | componentWillUpdate: 'DEFINE_MANY',
1673 |
1674 | /**
1675 | * Invoked when the component's DOM representation has been updated.
1676 | *
1677 | * Use this as an opportunity to operate on the DOM when the component has
1678 | * been updated.
1679 | *
1680 | * @param {object} prevProps
1681 | * @param {?object} prevState
1682 | * @param {?object} prevContext
1683 | * @param {DOMElement} rootNode DOM element representing the component.
1684 | * @optional
1685 | */
1686 | componentDidUpdate: 'DEFINE_MANY',
1687 |
1688 | /**
1689 | * Invoked when the component is about to be removed from its parent and have
1690 | * its DOM representation destroyed.
1691 | *
1692 | * Use this as an opportunity to deallocate any external resources.
1693 | *
1694 | * NOTE: There is no `componentDidUnmount` since your component will have been
1695 | * destroyed by that point.
1696 | *
1697 | * @optional
1698 | */
1699 | componentWillUnmount: 'DEFINE_MANY',
1700 |
1701 | /**
1702 | * Replacement for (deprecated) `componentWillMount`.
1703 | *
1704 | * @optional
1705 | */
1706 | UNSAFE_componentWillMount: 'DEFINE_MANY',
1707 |
1708 | /**
1709 | * Replacement for (deprecated) `componentWillReceiveProps`.
1710 | *
1711 | * @optional
1712 | */
1713 | UNSAFE_componentWillReceiveProps: 'DEFINE_MANY',
1714 |
1715 | /**
1716 | * Replacement for (deprecated) `componentWillUpdate`.
1717 | *
1718 | * @optional
1719 | */
1720 | UNSAFE_componentWillUpdate: 'DEFINE_MANY',
1721 |
1722 | // ==== Advanced methods ====
1723 |
1724 | /**
1725 | * Updates the component's currently mounted DOM representation.
1726 | *
1727 | * By default, this implements React's rendering and reconciliation algorithm.
1728 | * Sophisticated clients may wish to override this.
1729 | *
1730 | * @param {ReactReconcileTransaction} transaction
1731 | * @internal
1732 | * @overridable
1733 | */
1734 | updateComponent: 'OVERRIDE_BASE'
1735 | };
1736 |
1737 | /**
1738 | * Similar to ReactClassInterface but for static methods.
1739 | */
1740 | var ReactClassStaticInterface = {
1741 | /**
1742 | * This method is invoked after a component is instantiated and when it
1743 | * receives new props. Return an object to update state in response to
1744 | * prop changes. Return null to indicate no change to state.
1745 | *
1746 | * If an object is returned, its keys will be merged into the existing state.
1747 | *
1748 | * @return {object || null}
1749 | * @optional
1750 | */
1751 | getDerivedStateFromProps: 'DEFINE_MANY_MERGED'
1752 | };
1753 |
1754 | /**
1755 | * Mapping from class specification keys to special processing functions.
1756 | *
1757 | * Although these are declared like instance properties in the specification
1758 | * when defining classes using `React.createClass`, they are actually static
1759 | * and are accessible on the constructor instead of the prototype. Despite
1760 | * being static, they must be defined outside of the "statics" key under
1761 | * which all other static methods are defined.
1762 | */
1763 | var RESERVED_SPEC_KEYS = {
1764 | displayName: function(Constructor, displayName) {
1765 | Constructor.displayName = displayName;
1766 | },
1767 | mixins: function(Constructor, mixins) {
1768 | if (mixins) {
1769 | for (var i = 0; i < mixins.length; i++) {
1770 | mixSpecIntoComponent(Constructor, mixins[i]);
1771 | }
1772 | }
1773 | },
1774 | childContextTypes: function(Constructor, childContextTypes) {
1775 | if (process.env.NODE_ENV !== 'production') {
1776 | validateTypeDef(Constructor, childContextTypes, 'childContext');
1777 | }
1778 | Constructor.childContextTypes = _assign(
1779 | {},
1780 | Constructor.childContextTypes,
1781 | childContextTypes
1782 | );
1783 | },
1784 | contextTypes: function(Constructor, contextTypes) {
1785 | if (process.env.NODE_ENV !== 'production') {
1786 | validateTypeDef(Constructor, contextTypes, 'context');
1787 | }
1788 | Constructor.contextTypes = _assign(
1789 | {},
1790 | Constructor.contextTypes,
1791 | contextTypes
1792 | );
1793 | },
1794 | /**
1795 | * Special case getDefaultProps which should move into statics but requires
1796 | * automatic merging.
1797 | */
1798 | getDefaultProps: function(Constructor, getDefaultProps) {
1799 | if (Constructor.getDefaultProps) {
1800 | Constructor.getDefaultProps = createMergedResultFunction(
1801 | Constructor.getDefaultProps,
1802 | getDefaultProps
1803 | );
1804 | } else {
1805 | Constructor.getDefaultProps = getDefaultProps;
1806 | }
1807 | },
1808 | propTypes: function(Constructor, propTypes) {
1809 | if (process.env.NODE_ENV !== 'production') {
1810 | validateTypeDef(Constructor, propTypes, 'prop');
1811 | }
1812 | Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes);
1813 | },
1814 | statics: function(Constructor, statics) {
1815 | mixStaticSpecIntoComponent(Constructor, statics);
1816 | },
1817 | autobind: function() {}
1818 | };
1819 |
1820 | function validateTypeDef(Constructor, typeDef, location) {
1821 | for (var propName in typeDef) {
1822 | if (typeDef.hasOwnProperty(propName)) {
1823 | // use a warning instead of an _invariant so components
1824 | // don't show up in prod but only in __DEV__
1825 | if (process.env.NODE_ENV !== 'production') {
1826 | warning(
1827 | typeof typeDef[propName] === 'function',
1828 | '%s: %s type `%s` is invalid; it must be a function, usually from ' +
1829 | 'React.PropTypes.',
1830 | Constructor.displayName || 'ReactClass',
1831 | ReactPropTypeLocationNames[location],
1832 | propName
1833 | );
1834 | }
1835 | }
1836 | }
1837 | }
1838 |
1839 | function validateMethodOverride(isAlreadyDefined, name) {
1840 | var specPolicy = ReactClassInterface.hasOwnProperty(name)
1841 | ? ReactClassInterface[name]
1842 | : null;
1843 |
1844 | // Disallow overriding of base class methods unless explicitly allowed.
1845 | if (ReactClassMixin.hasOwnProperty(name)) {
1846 | _invariant(
1847 | specPolicy === 'OVERRIDE_BASE',
1848 | 'ReactClassInterface: You are attempting to override ' +
1849 | '`%s` from your class specification. Ensure that your method names ' +
1850 | 'do not overlap with React methods.',
1851 | name
1852 | );
1853 | }
1854 |
1855 | // Disallow defining methods more than once unless explicitly allowed.
1856 | if (isAlreadyDefined) {
1857 | _invariant(
1858 | specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED',
1859 | 'ReactClassInterface: You are attempting to define ' +
1860 | '`%s` on your component more than once. This conflict may be due ' +
1861 | 'to a mixin.',
1862 | name
1863 | );
1864 | }
1865 | }
1866 |
1867 | /**
1868 | * Mixin helper which handles policy validation and reserved
1869 | * specification keys when building React classes.
1870 | */
1871 | function mixSpecIntoComponent(Constructor, spec) {
1872 | if (!spec) {
1873 | if (process.env.NODE_ENV !== 'production') {
1874 | var typeofSpec = typeof spec;
1875 | var isMixinValid = typeofSpec === 'object' && spec !== null;
1876 |
1877 | if (process.env.NODE_ENV !== 'production') {
1878 | warning(
1879 | isMixinValid,
1880 | "%s: You're attempting to include a mixin that is either null " +
1881 | 'or not an object. Check the mixins included by the component, ' +
1882 | 'as well as any mixins they include themselves. ' +
1883 | 'Expected object but got %s.',
1884 | Constructor.displayName || 'ReactClass',
1885 | spec === null ? null : typeofSpec
1886 | );
1887 | }
1888 | }
1889 |
1890 | return;
1891 | }
1892 |
1893 | _invariant(
1894 | typeof spec !== 'function',
1895 | "ReactClass: You're attempting to " +
1896 | 'use a component class or function as a mixin. Instead, just use a ' +
1897 | 'regular object.'
1898 | );
1899 | _invariant(
1900 | !isValidElement(spec),
1901 | "ReactClass: You're attempting to " +
1902 | 'use a component as a mixin. Instead, just use a regular object.'
1903 | );
1904 |
1905 | var proto = Constructor.prototype;
1906 | var autoBindPairs = proto.__reactAutoBindPairs;
1907 |
1908 | // By handling mixins before any other properties, we ensure the same
1909 | // chaining order is applied to methods with DEFINE_MANY policy, whether
1910 | // mixins are listed before or after these methods in the spec.
1911 | if (spec.hasOwnProperty(MIXINS_KEY)) {
1912 | RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
1913 | }
1914 |
1915 | for (var name in spec) {
1916 | if (!spec.hasOwnProperty(name)) {
1917 | continue;
1918 | }
1919 |
1920 | if (name === MIXINS_KEY) {
1921 | // We have already handled mixins in a special case above.
1922 | continue;
1923 | }
1924 |
1925 | var property = spec[name];
1926 | var isAlreadyDefined = proto.hasOwnProperty(name);
1927 | validateMethodOverride(isAlreadyDefined, name);
1928 |
1929 | if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
1930 | RESERVED_SPEC_KEYS[name](Constructor, property);
1931 | } else {
1932 | // Setup methods on prototype:
1933 | // The following member methods should not be automatically bound:
1934 | // 1. Expected ReactClass methods (in the "interface").
1935 | // 2. Overridden methods (that were mixed in).
1936 | var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
1937 | var isFunction = typeof property === 'function';
1938 | var shouldAutoBind =
1939 | isFunction &&
1940 | !isReactClassMethod &&
1941 | !isAlreadyDefined &&
1942 | spec.autobind !== false;
1943 |
1944 | if (shouldAutoBind) {
1945 | autoBindPairs.push(name, property);
1946 | proto[name] = property;
1947 | } else {
1948 | if (isAlreadyDefined) {
1949 | var specPolicy = ReactClassInterface[name];
1950 |
1951 | // These cases should already be caught by validateMethodOverride.
1952 | _invariant(
1953 | isReactClassMethod &&
1954 | (specPolicy === 'DEFINE_MANY_MERGED' ||
1955 | specPolicy === 'DEFINE_MANY'),
1956 | 'ReactClass: Unexpected spec policy %s for key %s ' +
1957 | 'when mixing in component specs.',
1958 | specPolicy,
1959 | name
1960 | );
1961 |
1962 | // For methods which are defined more than once, call the existing
1963 | // methods before calling the new property, merging if appropriate.
1964 | if (specPolicy === 'DEFINE_MANY_MERGED') {
1965 | proto[name] = createMergedResultFunction(proto[name], property);
1966 | } else if (specPolicy === 'DEFINE_MANY') {
1967 | proto[name] = createChainedFunction(proto[name], property);
1968 | }
1969 | } else {
1970 | proto[name] = property;
1971 | if (process.env.NODE_ENV !== 'production') {
1972 | // Add verbose displayName to the function, which helps when looking
1973 | // at profiling tools.
1974 | if (typeof property === 'function' && spec.displayName) {
1975 | proto[name].displayName = spec.displayName + '_' + name;
1976 | }
1977 | }
1978 | }
1979 | }
1980 | }
1981 | }
1982 | }
1983 |
1984 | function mixStaticSpecIntoComponent(Constructor, statics) {
1985 | if (!statics) {
1986 | return;
1987 | }
1988 |
1989 | for (var name in statics) {
1990 | var property = statics[name];
1991 | if (!statics.hasOwnProperty(name)) {
1992 | continue;
1993 | }
1994 |
1995 | var isReserved = name in RESERVED_SPEC_KEYS;
1996 | _invariant(
1997 | !isReserved,
1998 | 'ReactClass: You are attempting to define a reserved ' +
1999 | 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
2000 | 'as an instance property instead; it will still be accessible on the ' +
2001 | 'constructor.',
2002 | name
2003 | );
2004 |
2005 | var isAlreadyDefined = name in Constructor;
2006 | if (isAlreadyDefined) {
2007 | var specPolicy = ReactClassStaticInterface.hasOwnProperty(name)
2008 | ? ReactClassStaticInterface[name]
2009 | : null;
2010 |
2011 | _invariant(
2012 | specPolicy === 'DEFINE_MANY_MERGED',
2013 | 'ReactClass: You are attempting to define ' +
2014 | '`%s` on your component more than once. This conflict may be ' +
2015 | 'due to a mixin.',
2016 | name
2017 | );
2018 |
2019 | Constructor[name] = createMergedResultFunction(Constructor[name], property);
2020 |
2021 | return;
2022 | }
2023 |
2024 | Constructor[name] = property;
2025 | }
2026 | }
2027 |
2028 | /**
2029 | * Merge two objects, but throw if both contain the same key.
2030 | *
2031 | * @param {object} one The first object, which is mutated.
2032 | * @param {object} two The second object
2033 | * @return {object} one after it has been mutated to contain everything in two.
2034 | */
2035 | function mergeIntoWithNoDuplicateKeys(one, two) {
2036 | _invariant(
2037 | one && two && typeof one === 'object' && typeof two === 'object',
2038 | 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
2039 | );
2040 |
2041 | for (var key in two) {
2042 | if (two.hasOwnProperty(key)) {
2043 | _invariant(
2044 | one[key] === undefined,
2045 | 'mergeIntoWithNoDuplicateKeys(): ' +
2046 | 'Tried to merge two objects with the same key: `%s`. This conflict ' +
2047 | 'may be due to a mixin; in particular, this may be caused by two ' +
2048 | 'getInitialState() or getDefaultProps() methods returning objects ' +
2049 | 'with clashing keys.',
2050 | key
2051 | );
2052 | one[key] = two[key];
2053 | }
2054 | }
2055 | return one;
2056 | }
2057 |
2058 | /**
2059 | * Creates a function that invokes two functions and merges their return values.
2060 | *
2061 | * @param {function} one Function to invoke first.
2062 | * @param {function} two Function to invoke second.
2063 | * @return {function} Function that invokes the two argument functions.
2064 | * @private
2065 | */
2066 | function createMergedResultFunction(one, two) {
2067 | return function mergedResult() {
2068 | var a = one.apply(this, arguments);
2069 | var b = two.apply(this, arguments);
2070 | if (a == null) {
2071 | return b;
2072 | } else if (b == null) {
2073 | return a;
2074 | }
2075 | var c = {};
2076 | mergeIntoWithNoDuplicateKeys(c, a);
2077 | mergeIntoWithNoDuplicateKeys(c, b);
2078 | return c;
2079 | };
2080 | }
2081 |
2082 | /**
2083 | * Creates a function that invokes two functions and ignores their return vales.
2084 | *
2085 | * @param {function} one Function to invoke first.
2086 | * @param {function} two Function to invoke second.
2087 | * @return {function} Function that invokes the two argument functions.
2088 | * @private
2089 | */
2090 | function createChainedFunction(one, two) {
2091 | return function chainedFunction() {
2092 | one.apply(this, arguments);
2093 | two.apply(this, arguments);
2094 | };
2095 | }
2096 |
2097 | /**
2098 | * Binds a method to the component.
2099 | *
2100 | * @param {object} component Component whose method is going to be bound.
2101 | * @param {function} method Method to be bound.
2102 | * @return {function} The bound method.
2103 | */
2104 | function bindAutoBindMethod(component, method) {
2105 | var boundMethod = method.bind(component);
2106 | if (process.env.NODE_ENV !== 'production') {
2107 | boundMethod.__reactBoundContext = component;
2108 | boundMethod.__reactBoundMethod = method;
2109 | boundMethod.__reactBoundArguments = null;
2110 | var componentName = component.constructor.displayName;
2111 | var _bind = boundMethod.bind;
2112 | boundMethod.bind = function(newThis) {
2113 | for (
2114 | var _len = arguments.length,
2115 | args = Array(_len > 1 ? _len - 1 : 0),
2116 | _key = 1;
2117 | _key < _len;
2118 | _key++
2119 | ) {
2120 | args[_key - 1] = arguments[_key];
2121 | }
2122 |
2123 | // User is trying to bind() an autobound method; we effectively will
2124 | // ignore the value of "this" that the user is trying to use, so
2125 | // let's warn.
2126 | if (newThis !== component && newThis !== null) {
2127 | if (process.env.NODE_ENV !== 'production') {
2128 | warning(
2129 | false,
2130 | 'bind(): React component methods may only be bound to the ' +
2131 | 'component instance. See %s',
2132 | componentName
2133 | );
2134 | }
2135 | } else if (!args.length) {
2136 | if (process.env.NODE_ENV !== 'production') {
2137 | warning(
2138 | false,
2139 | 'bind(): You are binding a component method to the component. ' +
2140 | 'React does this for you automatically in a high-performance ' +
2141 | 'way, so you can safely remove this call. See %s',
2142 | componentName
2143 | );
2144 | }
2145 | return boundMethod;
2146 | }
2147 | var reboundMethod = _bind.apply(boundMethod, arguments);
2148 | reboundMethod.__reactBoundContext = component;
2149 | reboundMethod.__reactBoundMethod = method;
2150 | reboundMethod.__reactBoundArguments = args;
2151 | return reboundMethod;
2152 | };
2153 | }
2154 | return boundMethod;
2155 | }
2156 |
2157 | /**
2158 | * Binds all auto-bound methods in a component.
2159 | *
2160 | * @param {object} component Component whose method is going to be bound.
2161 | */
2162 | function bindAutoBindMethods(component) {
2163 | var pairs = component.__reactAutoBindPairs;
2164 | for (var i = 0; i < pairs.length; i += 2) {
2165 | var autoBindKey = pairs[i];
2166 | var method = pairs[i + 1];
2167 | component[autoBindKey] = bindAutoBindMethod(component, method);
2168 | }
2169 | }
2170 |
2171 | var IsMountedPreMixin = {
2172 | componentDidMount: function() {
2173 | this.__isMounted = true;
2174 | }
2175 | };
2176 |
2177 | var IsMountedPostMixin = {
2178 | componentWillUnmount: function() {
2179 | this.__isMounted = false;
2180 | }
2181 | };
2182 |
2183 | /**
2184 | * Add more to the ReactClass base class. These are all legacy features and
2185 | * therefore not already part of the modern ReactComponent.
2186 | */
2187 | var ReactClassMixin = {
2188 | /**
2189 | * TODO: This will be deprecated because state should always keep a consistent
2190 | * type signature and the only use case for this, is to avoid that.
2191 | */
2192 | replaceState: function(newState, callback) {
2193 | this.updater.enqueueReplaceState(this, newState, callback);
2194 | },
2195 |
2196 | /**
2197 | * Checks whether or not this composite component is mounted.
2198 | * @return {boolean} True if mounted, false otherwise.
2199 | * @protected
2200 | * @final
2201 | */
2202 | isMounted: function() {
2203 | if (process.env.NODE_ENV !== 'production') {
2204 | warning(
2205 | this.__didWarnIsMounted,
2206 | '%s: isMounted is deprecated. Instead, make sure to clean up ' +
2207 | 'subscriptions and pending requests in componentWillUnmount to ' +
2208 | 'prevent memory leaks.',
2209 | (this.constructor && this.constructor.displayName) ||
2210 | this.name ||
2211 | 'Component'
2212 | );
2213 | this.__didWarnIsMounted = true;
2214 | }
2215 | return !!this.__isMounted;
2216 | }
2217 | };
2218 |
2219 | var ReactClassComponent = function() {};
2220 | _assign(
2221 | ReactClassComponent.prototype,
2222 | ReactComponent.prototype,
2223 | ReactClassMixin
2224 | );
2225 |
2226 | /**
2227 | * Creates a composite component class given a class specification.
2228 | * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
2229 | *
2230 | * @param {object} spec Class specification (which must define `render`).
2231 | * @return {function} Component constructor function.
2232 | * @public
2233 | */
2234 | function createClass(spec) {
2235 | // To keep our warnings more understandable, we'll use a little hack here to
2236 | // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
2237 | // unnecessarily identify a class without displayName as 'Constructor'.
2238 | var Constructor = identity(function(props, context, updater) {
2239 | // This constructor gets overridden by mocks. The argument is used
2240 | // by mocks to assert on what gets mounted.
2241 |
2242 | if (process.env.NODE_ENV !== 'production') {
2243 | warning(
2244 | this instanceof Constructor,
2245 | 'Something is calling a React component directly. Use a factory or ' +
2246 | 'JSX instead. See: https://fb.me/react-legacyfactory'
2247 | );
2248 | }
2249 |
2250 | // Wire up auto-binding
2251 | if (this.__reactAutoBindPairs.length) {
2252 | bindAutoBindMethods(this);
2253 | }
2254 |
2255 | this.props = props;
2256 | this.context = context;
2257 | this.refs = emptyObject;
2258 | this.updater = updater || ReactNoopUpdateQueue;
2259 |
2260 | this.state = null;
2261 |
2262 | // ReactClasses doesn't have constructors. Instead, they use the
2263 | // getInitialState and componentWillMount methods for initialization.
2264 |
2265 | var initialState = this.getInitialState ? this.getInitialState() : null;
2266 | if (process.env.NODE_ENV !== 'production') {
2267 | // We allow auto-mocks to proceed as if they're returning null.
2268 | if (
2269 | initialState === undefined &&
2270 | this.getInitialState._isMockFunction
2271 | ) {
2272 | // This is probably bad practice. Consider warning here and
2273 | // deprecating this convenience.
2274 | initialState = null;
2275 | }
2276 | }
2277 | _invariant(
2278 | typeof initialState === 'object' && !Array.isArray(initialState),
2279 | '%s.getInitialState(): must return an object or null',
2280 | Constructor.displayName || 'ReactCompositeComponent'
2281 | );
2282 |
2283 | this.state = initialState;
2284 | });
2285 | Constructor.prototype = new ReactClassComponent();
2286 | Constructor.prototype.constructor = Constructor;
2287 | Constructor.prototype.__reactAutoBindPairs = [];
2288 |
2289 | injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));
2290 |
2291 | mixSpecIntoComponent(Constructor, IsMountedPreMixin);
2292 | mixSpecIntoComponent(Constructor, spec);
2293 | mixSpecIntoComponent(Constructor, IsMountedPostMixin);
2294 |
2295 | // Initialize the defaultProps property after all mixins have been merged.
2296 | if (Constructor.getDefaultProps) {
2297 | Constructor.defaultProps = Constructor.getDefaultProps();
2298 | }
2299 |
2300 | if (process.env.NODE_ENV !== 'production') {
2301 | // This is a tag to indicate that the use of these method names is ok,
2302 | // since it's used with createClass. If it's not, then it's likely a
2303 | // mistake so we'll warn you to use the static property, property
2304 | // initializer or constructor respectively.
2305 | if (Constructor.getDefaultProps) {
2306 | Constructor.getDefaultProps.isReactClassApproved = {};
2307 | }
2308 | if (Constructor.prototype.getInitialState) {
2309 | Constructor.prototype.getInitialState.isReactClassApproved = {};
2310 | }
2311 | }
2312 |
2313 | _invariant(
2314 | Constructor.prototype.render,
2315 | 'createClass(...): Class specification must implement a `render` method.'
2316 | );
2317 |
2318 | if (process.env.NODE_ENV !== 'production') {
2319 | warning(
2320 | !Constructor.prototype.componentShouldUpdate,
2321 | '%s has a method called ' +
2322 | 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
2323 | 'The name is phrased as a question because the function is ' +
2324 | 'expected to return a value.',
2325 | spec.displayName || 'A component'
2326 | );
2327 | warning(
2328 | !Constructor.prototype.componentWillRecieveProps,
2329 | '%s has a method called ' +
2330 | 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
2331 | spec.displayName || 'A component'
2332 | );
2333 | warning(
2334 | !Constructor.prototype.UNSAFE_componentWillRecieveProps,
2335 | '%s has a method called UNSAFE_componentWillRecieveProps(). ' +
2336 | 'Did you mean UNSAFE_componentWillReceiveProps()?',
2337 | spec.displayName || 'A component'
2338 | );
2339 | }
2340 |
2341 | // Reduce time spent doing lookups by setting these on the prototype.
2342 | for (var methodName in ReactClassInterface) {
2343 | if (!Constructor.prototype[methodName]) {
2344 | Constructor.prototype[methodName] = null;
2345 | }
2346 | }
2347 |
2348 | return Constructor;
2349 | }
2350 |
2351 | return createClass;
2352 | }
2353 |
2354 | module.exports = factory;
2355 |
2356 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
2357 |
2358 | /***/ }),
2359 | /* 15 */
2360 | /***/ (function(module, exports, __webpack_require__) {
2361 |
2362 | /* WEBPACK VAR INJECTION */(function(process) {/**
2363 | * Copyright (c) 2013-present, Facebook, Inc.
2364 | *
2365 | * This source code is licensed under the MIT license found in the
2366 | * LICENSE file in the root directory of this source tree.
2367 | *
2368 | */
2369 |
2370 | 'use strict';
2371 |
2372 | var emptyObject = {};
2373 |
2374 | if (process.env.NODE_ENV !== 'production') {
2375 | Object.freeze(emptyObject);
2376 | }
2377 |
2378 | module.exports = emptyObject;
2379 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
2380 |
2381 | /***/ }),
2382 | /* 16 */
2383 | /***/ (function(module, exports) {
2384 |
2385 | "use strict";
2386 |
2387 | Object.defineProperty(exports, "__esModule", {
2388 | value: true
2389 | });
2390 |
2391 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
2392 |
2393 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2394 |
2395 | var Experiment = function () {
2396 | function Experiment() {
2397 | _classCallCheck(this, Experiment);
2398 | }
2399 |
2400 | _createClass(Experiment, [{
2401 | key: "get",
2402 | value: function get(parameter) {
2403 | throw "IMPLEMENT get";
2404 | }
2405 | }, {
2406 | key: "logExposure",
2407 | value: function logExposure(opts) {
2408 | throw "IMPLEMENT logExposure";
2409 | }
2410 | }, {
2411 | key: "getName",
2412 | value: function getName() {
2413 | throw "IMPLEMENT getName";
2414 | }
2415 | }, {
2416 | key: "previouslyLogged",
2417 | value: function previouslyLogged() {
2418 | throw "IMPLEMENT previouslyLogged";
2419 | }
2420 | }, {
2421 | key: "shouldFetchExperimentParameter",
2422 | value: function shouldFetchExperimentParameter(name) {
2423 | throw "IMPLEMENT shouldFetchExperimentParameter";
2424 | }
2425 | }]);
2426 |
2427 | return Experiment;
2428 | }();
2429 |
2430 | exports.default = Experiment;
2431 | ;
2432 | module.exports = exports["default"];
2433 |
2434 | /***/ }),
2435 | /* 17 */
2436 | /***/ (function(module, exports, __webpack_require__) {
2437 |
2438 | 'use strict';
2439 |
2440 | Object.defineProperty(exports, "__esModule", {
2441 | value: true
2442 | });
2443 |
2444 | var _react = __webpack_require__(2);
2445 |
2446 | var _react2 = _interopRequireDefault(_react);
2447 |
2448 | var _createReactClass = __webpack_require__(13);
2449 |
2450 | var _createReactClass2 = _interopRequireDefault(_createReactClass);
2451 |
2452 | var _parametrize = __webpack_require__(18);
2453 |
2454 | var _parametrize2 = _interopRequireDefault(_parametrize);
2455 |
2456 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2457 |
2458 | var ABTest = (0, _createReactClass2.default)({
2459 | displayName: 'ABTest',
2460 | getInitialState: function getInitialState() {
2461 | return {
2462 | hasRendered: false
2463 | };
2464 | },
2465 | enrolledInVariation: function enrolledInVariation() {
2466 | if (!this.state.hasRendered) {
2467 | this.setState({
2468 | hasRendered: true
2469 | });
2470 | }
2471 | },
2472 | renderExposedVariation: function renderExposedVariation() {
2473 | var _props = this.props,
2474 | on = _props.on,
2475 | experiment = _props.experiment;
2476 |
2477 |
2478 | if (!experiment) {
2479 | console.error("You must pass in an experiment instance as a prop");
2480 | return null;
2481 | } else if (!on) {
2482 | console.error("You must pass an 'on' prop indicating what parameter you want to branch off");
2483 | return null;
2484 | }
2485 |
2486 | return _react2.default.createElement(
2487 | _parametrize2.default,
2488 | {
2489 | experiment: experiment,
2490 | params: [on],
2491 | on: on,
2492 | enrolledInVariation: this.enrolledInVariation,
2493 | hasRendered: this.state.hasRendered },
2494 | this.props.children
2495 | );
2496 | },
2497 | render: function render() {
2498 | return this.renderExposedVariation();
2499 | }
2500 | });
2501 |
2502 | exports.default = ABTest;
2503 | module.exports = exports['default'];
2504 |
2505 | /***/ }),
2506 | /* 18 */
2507 | /***/ (function(module, exports, __webpack_require__) {
2508 |
2509 | 'use strict';
2510 |
2511 | Object.defineProperty(exports, "__esModule", {
2512 | value: true
2513 | });
2514 |
2515 | var _react = __webpack_require__(2);
2516 |
2517 | var _react2 = _interopRequireDefault(_react);
2518 |
2519 | var _propTypes = __webpack_require__(3);
2520 |
2521 | var _propTypes2 = _interopRequireDefault(_propTypes);
2522 |
2523 | var _createReactClass = __webpack_require__(13);
2524 |
2525 | var _createReactClass2 = _interopRequireDefault(_createReactClass);
2526 |
2527 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2528 |
2529 | var Parametrize = (0, _createReactClass2.default)({
2530 | displayName: 'Parametrize',
2531 | getInitialState: function getInitialState() {
2532 | return {
2533 | experimentParameters: null
2534 | };
2535 | },
2536 |
2537 |
2538 | childContextTypes: {
2539 | experimentParameters: _propTypes2.default.object,
2540 | experimentProps: _propTypes2.default.object.isRequired
2541 | },
2542 |
2543 | getChildContext: function getChildContext() {
2544 | return {
2545 | experimentParameters: this.state.experimentParameters,
2546 | experimentProps: this.props
2547 | };
2548 | },
2549 | componentWillMount: function componentWillMount() {
2550 | this.fetchParameters();
2551 | },
2552 | fetchParameters: function fetchParameters() {
2553 | var _props = this.props,
2554 | experiment = _props.experiment,
2555 | params = _props.params;
2556 |
2557 |
2558 | if (!experiment || !experiment.get) {
2559 | console.error("You must pass in an experiment instance as a prop");
2560 | return;
2561 | } else if (!params) {
2562 | console.error("You mass pass a list of params in as a prop");
2563 | return;
2564 | }
2565 |
2566 | var paramsObj = {};
2567 | for (var i = 0; i < params.length; i++) {
2568 | var param = params[i];
2569 | var paramVal = experiment.get(param);
2570 | if (paramVal !== null && paramVal !== undefined) {
2571 | paramsObj[param] = paramVal;
2572 | }
2573 | }
2574 |
2575 | if (Object.keys(paramsObj).length !== 0 && experiment.previouslyLogged() === false) {
2576 | experiment.logExposure({
2577 | params: params,
2578 | name: experiment.getName()
2579 | });
2580 | }
2581 |
2582 | this.setState({
2583 | experimentParameters: paramsObj
2584 | });
2585 | },
2586 | renderExperiment: function renderExperiment() {
2587 | var _this = this;
2588 |
2589 | if (!this.state.experimentParameters) {
2590 | return null;
2591 | }
2592 |
2593 | var passThrough = this.props._passThrough;
2594 | var renderedChildren = _react2.default.Children.map(this.props.children, function (child) {
2595 | if (passThrough) {
2596 | return _react2.default.cloneElement(child, _this.state.experimentParameters);
2597 | } else {
2598 | return _react2.default.cloneElement(child, {});
2599 | }
2600 | });
2601 |
2602 | return _react2.default.createElement(
2603 | 'span',
2604 | null,
2605 | renderedChildren
2606 | );
2607 | },
2608 | render: function render() {
2609 | return this.renderExperiment();
2610 | }
2611 | });
2612 |
2613 | exports.default = Parametrize;
2614 | module.exports = exports['default'];
2615 |
2616 | /***/ }),
2617 | /* 19 */
2618 | /***/ (function(module, exports, __webpack_require__) {
2619 |
2620 | 'use strict';
2621 |
2622 | Object.defineProperty(exports, "__esModule", {
2623 | value: true
2624 | });
2625 |
2626 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
2627 |
2628 | var _react = __webpack_require__(2);
2629 |
2630 | var _react2 = _interopRequireDefault(_react);
2631 |
2632 | var _propTypes = __webpack_require__(3);
2633 |
2634 | var _propTypes2 = _interopRequireDefault(_propTypes);
2635 |
2636 | var _createReactClass = __webpack_require__(13);
2637 |
2638 | var _createReactClass2 = _interopRequireDefault(_createReactClass);
2639 |
2640 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2641 |
2642 | exports.default = function (Component) {
2643 | return (0, _createReactClass2.default)({
2644 | contextTypes: {
2645 | experimentParameters: _propTypes2.default.object.isRequired
2646 | },
2647 |
2648 | render: function render() {
2649 | return _react2.default.createElement(Component, _extends({}, this.props, this.context.experimentParameters));
2650 | }
2651 | });
2652 | };
2653 |
2654 | module.exports = exports['default'];
2655 |
2656 | /***/ }),
2657 | /* 20 */
2658 | /***/ (function(module, exports, __webpack_require__) {
2659 |
2660 | 'use strict';
2661 |
2662 | Object.defineProperty(exports, "__esModule", {
2663 | value: true
2664 | });
2665 |
2666 | var _react = __webpack_require__(2);
2667 |
2668 | var _react2 = _interopRequireDefault(_react);
2669 |
2670 | var _createReactClass = __webpack_require__(13);
2671 |
2672 | var _createReactClass2 = _interopRequireDefault(_createReactClass);
2673 |
2674 | var _parametrize = __webpack_require__(18);
2675 |
2676 | var _parametrize2 = _interopRequireDefault(_parametrize);
2677 |
2678 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2679 |
2680 | exports.default = function (experiment, experimentParams, Component) {
2681 | return (0, _createReactClass2.default)({
2682 | render: function render() {
2683 | return _react2.default.createElement(
2684 | _parametrize2.default,
2685 | { experiment: experiment, params: experimentParams, _passThrough: true },
2686 | _react2.default.createElement(Component, this.props)
2687 | );
2688 | }
2689 | });
2690 | };
2691 |
2692 | module.exports = exports['default'];
2693 |
2694 | /***/ })
2695 | /******/ ])
2696 | });
2697 | ;
--------------------------------------------------------------------------------
/dist/react-experiments.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactExperiments=t(require("react")):e.ReactExperiments=t(e.React)}(this,function(e){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),a=o(i),u=n(16),s=r(u),c=n(17),l=r(c),p=n(18),f=r(p),d=n(19),m=r(d),h=n(20),y=r(h);t.default={ABTest:l.default,When:a.When,Default:a.Default,Experiment:s.default,Parametrize:f.default,withExperimentParams:m.default,parametrize:y.default},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.Default=t.When=void 0;var o=n(2),i=r(o),a=n(3),u=r(a),s=n(13),c=r(s);t.When=(0,c.default)({displayName:"When",getInitialState:function(){return{shouldRender:!1}},contextTypes:{experimentParameters:u.default.object.isRequired,experimentProps:u.default.object.isRequired},componentWillUpdate:function(e,t){t.shouldRender&&this.context.experimentProps.enrolledInVariation()},componentDidMount:function(){this.shouldRenderVariation()},shouldRenderVariation:function(){var e=this.props.value,t=this.context.experimentProps.on;this.context.experimentParameters&&this.context.experimentParameters[t]===e&&this.setState({shouldRender:!0})},renderChildren:function(){return i.default.Children.map(this.props.children,function(e){return i.default.isValidElement(e)?i.default.cloneElement(e,{}):e})},render:function(){return this.state.shouldRender?i.default.createElement("span",{className:"experiment-variation-component"},this.renderChildren()):null}}),t.Default=(0,c.default)({displayName:"Default",contextTypes:{experimentProps:u.default.object.isRequired},render:function(){return this.context.experimentProps.hasRendered?null:i.default.createElement("span",null,this.props.children)}})},function(t,n){t.exports=e},function(e,t,n){(function(t){if("production"!==t.env.NODE_ENV){var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,o=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},i=!0;e.exports=n(5)(o,i)}else e.exports=n(12)()}).call(t,n(4))},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(e){if(l===setTimeout)return setTimeout(e,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(e,0);try{return l(e,0)}catch(t){try{return l.call(null,e,0)}catch(t){return l.call(this,e,0)}}}function i(e){if(p===clearTimeout)return clearTimeout(e);if((p===r||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(e);try{return p(e)}catch(t){try{return p.call(null,e)}catch(t){return p.call(this,e)}}}function a(){h&&d&&(h=!1,d.length?m=d.concat(m):y=-1,m.length&&u())}function u(){if(!h){var e=o(a);h=!0;for(var t=m.length;t;){for(d=m,m=[];++y1)for(var n=1;n>",A={array:d("array"),bool:d("boolean"),func:d("function"),number:d("number"),object:d("object"),string:d("string"),symbol:d("symbol"),any:m(),arrayOf:h,element:y(),instanceOf:v,node:b(),objectOf:g,oneOf:E,oneOfType:N,shape:_,exact:x};return p.prototype=Error.prototype,A.checkPropTypes=s,A.PropTypes=A,A}}).call(t,n(4))},function(e,t){"use strict";function n(e){return function(){return e}}var r=function(){};r.thatReturns=n,r.thatReturnsFalse=n(!1),r.thatReturnsTrue=n(!0),r.thatReturnsNull=n(null),r.thatReturnsThis=function(){return this},r.thatReturnsArgument=function(e){return e},e.exports=r},function(e,t,n){(function(t){"use strict";function n(e,t,n,o,i,a,u,s){if(r(t),!e){var c;if(void 0===t)c=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[n,o,i,a,u,s],p=0;c=new Error(t.replace(/%s/g,function(){return l[p++]})),c.name="Invariant Violation"}throw c.framesToPop=1,c}}var r=function(e){};"production"!==t.env.NODE_ENV&&(r=function(e){if(void 0===e)throw new Error("invariant requires an error message argument")}),e.exports=n}).call(t,n(4))},function(e,t,n){(function(t){"use strict";var r=n(6),o=r;if("production"!==t.env.NODE_ENV){var i=function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r2?n-2:0),o=2;o1?u-1:0),l=1;l
2 |
3 |
4 | react-experiments example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
91 |
178 |
179 |