[
  {
    "path": ".gitignore",
    "content": "/coverage\n/demo/dist\n/es\n/lib\n/node_modules\nnpm-debug.log*\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\n\nlanguage: node_js\nnode_js:\n  - 4\n  - 6\n  - 7\n  - 8\n\nbefore_install:\n  - npm install codecov.io coveralls\n\nafter_success:\n  - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js\n  - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\n\nbranches:\n  only:\n    - master\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Prerequisites\n\n[Node.js](http://nodejs.org/) >= v4 must be installed.\n\n## Installation\n\n- Running `npm install` in the components's root directory will install everything you need for development.\n\n## Demo Development Server\n\n- `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading.\n\n## Running Tests\n\n- `npm test` will run the tests once.\n\n- `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`.\n\n- `npm run test:watch` will run the tests on every change.\n\n## Building\n\n- `npm run build` will build the component for publishing to npm and also bundle the demo app.\n\n- `npm run clean` will delete built resources.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Patrick Smith\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# React Organism\n\n[![Travis][build-badge]][build]\n[![npm package][npm-badge]][npm]\n[![Coveralls][coveralls-badge]][coveralls]\n\n**Dead simple React/Preact state management to bring pure components alive**\n\n- Supports `async`/`await` and easy loading (e.g. `fetch()`)\n- Reload when particular props change\n- Animate using generator functions: just `yield` the new state for each frame\n- Tiny: 1.69 KB gzipped (3.49 KB uncompressed)\n- Embraces the existing functional `setState` while avoiding boilerplate (no writing `this.setState()` or `.bind` again)\n- Easy to unit test\n\n#### Table of contents\n\n- [Installation](#installation)\n- [Demos](#demos)\n- [Usage](#usage)\n  - [Basic](#basic)\n  - [Using props](#using-props)\n  - [Async & promises](#async)\n  - [Handling events](#handling-events)\n  - [Animation](#animation)\n  - [Serialization: Local storage](#serialization-local-storage)\n  - [Separate and reuse state handlers](#separate-and-reuse-state-handlers)\n  - [Multicelled organisms](#multicelled-organisms)\n- [API](#api)\n  - [`makeOrganism(PureComponent, StateFunctions, options)`](#makeorganismpurecomponent-statefunctions-options)\n  - [State functions](#state-functions)\n  - [Argument enhancers](#argument-enhancers)\n- [Why instead of Redux?](#why-instead-of-redux)\n\n## Installation\n\n```\nnpm i react-organism --save\n```\n\n## Demos\n\n- [Animated counter](https://codesandbox.io/s/2vx12v3qmn)\n- [Dynamic loading with `import()`](https://codesandbox.io/s/X6mLEwG7W)\n- [Live form error validation with Yup](https://codesandbox.io/s/4xQpKRRWx)\n- [Multicelled component — using multiple states](https://codesandbox.io/s/Yv7j1xLqM)\n- [Todo List](https://codesandbox.io/s/yME5Y3Yz)\n- [Inputs, forms, animation, fetch](https://react-organism.now.sh) · [code](https://github.com/BurntCaramel/react-organism/tree/master/demo/src)\n- [User Stories Maker](https://codesandbox.io/s/xkZ5ZONl)\n- [React Cheat Sheet](https://react-cheat.now.sh/) · [code](https://github.com/BurntCaramel/react-cheat)\n\n## Usage\n\n### Basic\n\n```js\n// organisms/Counter.js\nimport makeOrganism from 'react-organism'\nimport Counter from './components/Counter'\n\nexport default makeOrganism(Counter, {\n  initial: () => ({ count: 0 }),\n  increment: () => ({ count }) => ({ count: count + 1 }),\n  decrement: () => ({ count }) => ({ count: count - 1 })\n})\n```\n\n```js\n// components/Counter.js\nimport React, { Component } from 'react'\n\nexport default function Counter({\n  count,\n  handlers: {\n    increment,\n    decrement\n  }\n}) {\n  return (\n    <div>\n      <button onClick={ decrement } children='−' />\n      <span>{ count }</span>\n      <button onClick={ increment } children='+' />\n    </div>\n  )\n}\n```\n\n### Using props\n\nThe handlers can easily use props, which are always passed as the first argument\n\n```js\n// organisms/Counter.js\nimport makeOrganism from 'react-organism'\nimport Counter from './components/Counter'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  increment: ({ stride = 1 }) => ({ count }) => ({ count: count + stride }),\n  decrement: ({ stride = 1 }) => ({ count }) => ({ count: count - stride })\n})\n\n// Render passing prop: <CounterOrganism stride={ 20 } />\n```\n\n### Async\n\nAsynchronous code to load from an API is easy:\n\n```js\n// components/Items.js\nimport React, { Component } from 'react'\n\nexport default function Items({\n  items,\n  collectionName,\n  handlers: {\n    load\n  }\n}) {\n  return (\n    <div>\n      {\n        !!items ? (\n          `${items.length} ${collectionName}`\n        ) : (\n          'Loading…'\n        )\n      }\n      <div>\n        <button onClick={ load } children='Reload' />\n      </div>\n    </div>\n  )\n}\n```\n\n```js\n// organisms/Items.js\nimport makeOrganism from 'react-organism'\nimport Items from '../components/Items'\n\nconst baseURL = 'https://jsonplaceholder.typicode.com'\nconst fetchAPI = (path) => fetch(baseURL + path).then(r => r.json())\n\nexport default makeOrganism(Items, {\n  initial: () => ({ items: null }),\n\n  load: async ({ path }, prevProps) => {\n    if (!prevProps || path !== prevProps.path) {\n      return { items: await fetchAPI(path) }\n    }\n  }\n})\n```\n\n```js\n<div>\n  <ItemsOrganism path='/photos' collectionName='photos' />\n  <ItemsOrganism path='/todos' collectionName='todo items' />\n</div>\n```\n\n### Handling events\n\nHandlers can easily accept arguments such as events.\n\n```js\n// components/Calculator.js\nimport React, { Component } from 'react'\n\nexport default function Calculator({\n  value,\n  handlers: {\n    changeValue,\n    double,\n    add3,\n    initial\n  }\n}) {\n  return (\n    <div>\n      <input value={ value } onChange={ changeValue } />\n      <button onClick={ double } children='Double' />\n      <button onClick={ add3 } children='Add 3' />\n      <button onClick={ initial } children='reset' />\n    </div>\n  )\n}\n```\n\n```js\n// organisms/Calculator.js\nimport makeOrganism from 'react-organism'\nimport Calculator from '../components/Calculator'\n\nexport default makeOrganism(Calculator, {\n  initial: ({ initialValue = 0 }) => ({ value: initialValue }),\n  // Destructure event to get target\n  changeValue: (props, { target }) => ({ value }) => ({ value: parseInt(target.value, 10) }),\n  double: () => ({ value }) => ({ value: value * 2 }),\n  add3: () => ({ value }) => ({ value: value + 3 })\n})\n```\n\n### Animation\n\n```js\nimport makeOrganism from 'react-organism'\nimport Counter from '../components/Counter'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  increment: function * ({ stride = 20 }) {\n    while (stride > 0) {\n      yield ({ count }) => ({ count: count + 1 })\n      stride -= 1\n    }\n  },\n  decrement: function * ({ stride = 20 }) {\n    while (stride > 0) {\n      yield ({ count }) => ({ count: count - 1 })\n      stride -= 1\n    }\n  }\n})\n```\n\n### Automatically extract from `data-` attributes and `<forms>`\n\nExample coming soon\n\n### Serialization: Local storage\n\n```js\n// organisms/Counter.js\nimport makeOrganism from 'react-organism'\nimport Counter from '../components/Counter'\n\nconst localStorageKey = 'counter'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  load: async (props, prevProps) => {\n    if (!prevProps) {\n      // Try commenting out:\n      /* throw (new Error('Oops!')) */\n\n      // Load previously stored state, if present\n      return await JSON.parse(localStorage.getItem(localStorageKey))\n    }\n  },\n  increment: ({ stride = 1 }) => ({ count }) => ({ count: count + stride }),\n  decrement: ({ stride = 1 }) => ({ count }) => ({ count: count - stride })\n}, {\n  onChange(state) {\n    // When state changes, save in local storage\n    localStorage.setItem(localStorageKey, JSON.stringify(state))\n  }\n})\n```\n\n### Separate and reuse state handlers\n\nReact Organism supports separating state handlers and the component into their own files. This means state handlers could be reused by multiple smart components.\n\nHere’s an example of separating state:\n\n```js\n// state/counter.js\nexport const initial = () => ({\n  count: 0\n})\n\nexport const increment = () => ({ count }) => ({ count: count + 1 })\nexport const decrement = () => ({ count }) => ({ count: count - 1 })\n```\n\n```js\n// organisms/Counter.js\nimport makeOrganism from 'react-organism'\nimport Counter from './components/Counter'\nimport * as counterState from './state/counter'\n\nexport default makeOrganism(Counter, counterState)\n```\n\n```js\n// App.js\nimport React from 'react'\nimport CounterOrganism from './organisms/Counter'\n\nclass App extends React.Component {\n  render() {\n    return (\n      <div>\n        <CounterOrganism />\n      </div>\n    )\n  }\n}\n```\n\n### Multicelled Organisms\n\nExample coming soon.\n\n\n## API\n\n### `makeOrganism(PureComponent, StateFunctions, options?)`\n```js\nimport makeOrganism from 'react-organism'\n```\nCreates a smart component, rendering using React component `PureComponent`, and managing state using `StateFunctions`.\n\n#### `PureComponent`\nA React component, usually a pure functional component. This component is passed as its props:\n\n- The props passed to the smart component, combined with\n- The current state, combined with\n- `handlers` which correspond to each function in `StateFunctions` and are ready to be passed to e.g. `onClick`, `onChange`, etc.\n- `loadError?`: Error produced by the `load` handler\n- `handlerError?`: Error produced by any other handler\n\n#### `StateFunctions`\nObject with functional handlers. See [state functions below](#state-functions).\n\nEither pass a object directly with each function, or create a separate file with each handler function `export`ed out, and then bring in using `import * as StateFunctions from '...'`.\n\n#### `options`\n\n##### `adjustArgs?(args: array) => newArgs: array`\n\nUsed to enhance handlers. See [built-in handlers below](#argument-enhancers).\n\n##### `onChange?(state)`\n\nCalled after the state has changed, making it ideal for saving the state somewhere (e.g. Local Storage).\n\n\n### State functions\n\nYour state is handled by a collection of functions. Each function is pure: they can only rely on the props and state passed to them. Functions return the new state, either immediately or asynchronously.\n\nEach handler is passed the current props first, followed by the called arguments:\n- `(props, event)`: most event handlers, e.g. `onClick`, `onChange`\n- `(props, first, second)`: e.g. `handler(first, second)`\n- `(props, ...args)`: get all arguments passed\n- `(props)`: ignore any arguments\n- `()`: ignore props and arguments\n\nHandlers must return one of the following:\n- An object with new state changes, a la React’s `setState(changes)`.\n- A function accepting the previous state and current props, and returns the new state, a la React’s `setState((prevState, props) => changes)`.\n- A promise resolving to any of the above (object / function), which will then be used to update the state. Uncaught errors are stored in state under the key `handlerError`. Alternatively, your handler can use the `async`/`await` syntax.\n- An iterator, such as one made by using a [generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function%2A). Each object passed to `yield` may be one of the above (object / function / promise).\n- An array of any of the above (object / function / promise / iterator).\n- Or optionally, nothing.\n\nThere are some handlers for special tasks, specifically:\n\n#### `initial(props) => object` (required)\nReturn initial state to start off with, a la React’s `initialState`. Passed props.\n\n#### `load(props: object, prevProps: object?, { handlers: object }) => object | Promise<object> | void` (optional)\nPassed the current props and the previous props. Return new state, a Promise returning new state, or nothing. You may also use a generator function (`function * load(props, prevProps)`) and `yield` state changes.\n\nIf this is the first time loaded or if being reloaded, then `prevProps` is `null`.\n\nUsual pattern is to check for either `prevProps` being `null` or if the prop of interest has changed from its previous value:\n```js\nexport const load = async ({ id }, prevProps) => {\n  if (!prevProps || id !== prevProps.id) {\n    return { item: await loadItem(id) }\n  }\n}\n```\n\nYour `load` handler will be called in React’s lifecycle: `componentDidMount` and `componentWillReceiveProps`.\n\n\n### Argument enhancers\n\nHandler arguments can be adjusted, to cover many common cases. Pass them to the `adjustArgs` option. The following enhancers are built-in:\n\n#### `extractFromDOM(args: array) => newArgs: array`\n```js\nimport extractFromDOM from 'react-organism/lib/adjustArgs/extractFromDOM'\n```\n\nExtract values from DOM, specifically:\n- For events as the first argument, extracts `value`, `checked`, and `name` from `event.target`. Additionally, if target has `data-` attributes, these will also be extracted in camelCase from its [`dataset`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset). Suffixing `data-` attributes with `_number` will convert value to a number (instead of string) using `parseFloat`, and drop the suffix. Handler will receive these extracted values in an object as the first argument, followed by the original arguments.\n- For `submit` events, extracts values of `<input>` fields in a `<form>`. Handler will receive the values keyed by the each input’s `name` attribute, followed by the original arguments. Pass the handler to the `onSubmit` prop of the `<form>`. Form must have `data-extract` attribute present. To clear the form after submit, add `data-reset` to the form.\n\n\n## Why instead of Redux?\n\n- Like Redux, separate your state management from rendering\n- Unlike Redux, avoid loose strings for identifying actions\n- Redux encourages having state in one bundle, whereas dynamic `import()` encourages breaking apps into sections\n- Easier to reuse functionality, as action handlers are totally encapsulated\n- No ability to reach across to the other side of your state tree\n- Encourages composition of components\n- Supports `async` and `await` in any action\n- Supports generator functions to allow multiple state changes — great for animation\n- No `switch` statements\n- No boilerplate or additional helper libraries needed\n\n\n[build-badge]: https://img.shields.io/travis/RoyalIcing/react-organism/master.png?style=flat-square\n[build]: https://travis-ci.org/RoyalIcing/react-organism\n\n[npm-badge]: https://img.shields.io/npm/v/react-organism.png?style=flat-square\n[npm]: https://www.npmjs.org/package/react-organism\n\n[coveralls-badge]: https://img.shields.io/coveralls/RoyalIcing/react-organism/master.png?style=flat-square\n[coveralls]: https://coveralls.io/github/RoyalIcing/react-organism\n"
  },
  {
    "path": "demo/src/components/Calculator.js",
    "content": "import React, { Component } from 'react'\n\nexport default function Calculator({\n  value,\n  handlers: {\n    changeValue,\n    double,\n    add3,\n    initial\n  }\n}) {\n  return (\n    <div className='h-spaced'>\n      <input value={ value } onChange={ changeValue } />\n      <button onClick={ double } children='Double' />\n      <button onClick={ add3 } children='Add 3' />\n      <button onClick={ initial } children='Reset' />\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/Counter.js",
    "content": "import React, { Component } from 'react'\n\nexport default function Counter({\n  count,\n  handlers: {\n    increment,\n    decrement,\n    initial\n  }\n}) {\n  return (\n    <div className='h-spaced'>\n      <button onClick={ decrement } children='−' />\n      <span>{ count }</span>\n      <button onClick={ increment } children='+' />\n      <button onClick={ initial } children='Reset' />\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/FriendsList.js",
    "content": "import React, { Component } from 'react'\n\nexport default function FriendsList({\n  friendsList,\n  selectedIndex,\n  onSelectAtIndex,\n  handlers: {\n    addRandomFriend\n  }\n}) {\n  return (\n    <div>\n      {\n        !!friendsList ? (\n          friendsList.map((friend, index) => (\n            <div key={ index }\n              style={{\n                backgroundColor: selectedIndex === index ? '#00b4ff' : undefined\n              }}\n              data-index_number={ index }\n              onClick={ onSelectAtIndex }\n            >\n              Name: { friend.name }\n            </div>\n          ))\n        ) : (\n          'Loading…'\n        )\n      }\n      <div>\n        <button onClick={ addRandomFriend } children='Add random friend' />\n      </div>\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/Items.js",
    "content": "import React, { Component } from 'react'\n\nexport default function Counter({\n  items,\n  collectionName,\n  handlers: {\n    load\n  }\n}) {\n  return (\n    <div>\n      {\n        !!items ? (\n          `${items.length} ${collectionName}`\n        ) : (\n          'Loading…'\n        )\n      }\n      <div>\n        <button onClick={ load } children='Reload' />\n      </div>\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/Notifications.js",
    "content": "import React from 'react'\n\nexport default function Notifications({\n  friends: {\n    friendsList\n  },\n  photos: {\n    photosList\n  }\n}) {\n  return (\n    <div>\n      { `${friendsList.length} friends` }\n      { ' | ' }\n      { `${photosList.length} photos` }\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/PhotosList.js",
    "content": "import React, { Component } from 'react'\n\nexport default function PhotosList({\n  photosList,\n  handlers: {\n    addRandomPhoto,\n    addPhoto\n  }\n}) {\n  return (\n    <div>\n      {\n        !!photosList ? (\n          photosList.map((photo, index) => (\n            <div key={ index }>\n              <img src={ photo.url } />\n            </div>\n          ))\n        ) : (\n          'Loading…'\n        )\n      }\n      <div>\n        <form data-extract data-reset onSubmit={ addPhoto }>\n          <label>\n            {'URL: '}\n            <input type='url' name='url' />\n          </label>\n          <button type='submit' children='Add photo' />\n        </form>\n      </div>\n      <div>\n        <button onClick={ addRandomPhoto } children='Add random photo' />\n      </div>\n    </div>\n  )\n}"
  },
  {
    "path": "demo/src/components/Row.js",
    "content": "import React from 'react'\n\nconst style = {\n  display: 'flex',\n  flexDirection: 'row'\n}\n\nexport default function Row({\n  children\n}) {\n  return (\n    <div style={ style } children={ children } />\n  )\n}"
  },
  {
    "path": "demo/src/index.js",
    "content": "import React, { Component } from 'react'\nimport { render } from 'react-dom'\n\nimport CounterOrganism from './organisms/Counter'\nimport Counter2Organism from './organisms/Counter2'\nimport Counter3Organism from './organisms/Counter3'\nimport Counter4Organism from './organisms/Counter4'\nimport ItemsOrganism from './organisms/Items'\nimport ItemsChoiceOrganism from './organisms/ItemsChoice'\nimport CalculatorOrganism from './organisms/Calculator'\nimport SocialOrganism from './organisms/Social'\n\nclass Demo extends Component {\n  render() {\n    return <div>\n      <h1><a href=\"https://github.com/RoyalIcing/react-organism\">react-organism</a></h1>\n      <h3>Simple counter:</h3>\n      <CounterOrganism />\n      <hr />\n      <h3>Using props to customize:</h3>\n      <Counter2Organism initialCount={ 9 } stride={ 3 } />\n      <hr />\n      <h3>Local storage (change and reload page):</h3>\n      <Counter3Organism />\n      <hr />\n      <h3>Async animated:</h3>\n      <Counter4Organism />\n      <hr />\n      <h3>Load data from API:</h3>\n      <ItemsOrganism path='/posts' collectionName='posts' />\n      <hr />\n      <ItemsOrganism path='/photos' collectionName='photos' />\n      <hr />\n      <ItemsOrganism path='/todos' collectionName='todos' />\n      <hr />\n      <h3>Handling prop changes:</h3>\n      <ItemsChoiceOrganism />\n      <hr />\n      <h3>Event handlers with calculator:</h3>\n      <CalculatorOrganism />\n      <hr />\n      <h3>Multi-celled organism</h3>\n      <SocialOrganism darkMode />\n\n      <style>{`\n* {\n  padding: 0;\n  font-size: inherit;\n  box-sizing: border-box;\n}\n\nhtml {\n  font-size: 18px;\n  font-family: system, \"-apple-system\", \"-webkit-system-font\", BlinkMacSystemFont, \"Helvetica Neue\", \"Helvetica\", \"Segoe UI\", \"Roboto\", \"Arial\", \"freesans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  line-height: 1.3;\n}\n\na {\n  color: inherit;\n}\n\nh1 {\n  font-size: 1.5rem;\n}\n\nbutton, input {\n  padding: 0.2em 0.5em;\n  border: 1px solid #ccc;\n  border-radius: 0.25em;\n}\nbutton {\n  color: #222;\n  background: #eee;\n}\n\nhr {\n  border: none;\n  border-top: 1px solid #ccc;\n}\n\n.h-spaced > * {\n  margin-right: 0.5em;\n}\n`}</style>\n    </div>\n  }\n}\n\nrender(<Demo/>, document.querySelector('#demo'))\n"
  },
  {
    "path": "demo/src/organisms/Calculator.js",
    "content": "import makeOrganism from '../../../src'\nimport extractFromDOM from '../../../src/adjustArgs/extractFromDOM'\nimport Calculator from '../components/Calculator'\n\nexport default makeOrganism(Calculator, {\n  initial: ({ initialValue = 0 }) => ({ value: initialValue }),\n  changeValue: (props, { value }) => ({ value: parseInt(value, 10) || '' }),\n  // Or more robust number input handling with fallback to previous value:\n  // changeValue: (props, { target: { value: newValue } }) => ({ value: previousValue }) => ({\n  //   value: newValue && (parseInt(newValue, 10) || previousValue)\n  // }),\n  double: () => ({ value }) => ({ value: (value || 0) * 2 }),\n  add3: () => ({ value }) => ({ value: (value || 0) + 3 })\n}, {\n  adjustArgs: extractFromDOM\n})\n"
  },
  {
    "path": "demo/src/organisms/Counter.js",
    "content": "import makeOrganism from '../../../src'\nimport * as counterState from '../state/counter'\nimport Counter from '../components/Counter'\n\n//export default makeOrganism(Counter, counterState)\n\nexport default makeOrganism(Counter, {\n  initial: () => ({ count: 0 }),\n  increment: () => ({ count }) => ({ count: count + 1 }),\n  decrement: () => ({ count }) => ({ count: count - 1 })\n})\n"
  },
  {
    "path": "demo/src/organisms/Counter2.js",
    "content": "import makeOrganism from '../../../src'\nimport Counter from '../components/Counter'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  increment: () => ({ count }, { stride = 1 }) => ({ count: count + stride }),\n  decrement: () => ({ count }, { stride = 1 }) => ({ count: count - stride })\n})\n"
  },
  {
    "path": "demo/src/organisms/Counter3.js",
    "content": "import makeOrganism from '../../../src'\nimport Counter from '../components/Counter'\n\nconst localStorageKey = 'counter3'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 13 }) => ({ count: initialCount }),\n  load: async (props, prevProps) => {\n    if (!prevProps) {\n      // Try commenting out:\n      /* throw (new Error('Oops!')) */\n\n      // Load previously stored state, if present\n      return await JSON.parse(localStorage.getItem(localStorageKey))\n    }\n  },\n  increment: ({ stride = 1 }) => ({ count }) => ({ count: count + stride }),\n  decrement: ({ stride = 1 }) => ({ count }) => ({ count: count - stride })\n}, {\n  onChange(state) {\n    // When state changes, save in local storage\n    localStorage.setItem(localStorageKey, JSON.stringify(state))\n  }\n})\n"
  },
  {
    "path": "demo/src/organisms/Counter4.js",
    "content": "import makeOrganism from '../../../src'\nimport Counter from '../components/Counter'\n\nexport default makeOrganism(Counter, {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  increment: function * ({ stride = 20 }) {\n    while (stride > 0) {\n      yield ({ count }) => ({ count: count + 1 })\n      stride -= 1\n    }\n  },\n  decrement: function * ({ stride = 20 }) {\n    while (stride > 0) {\n      yield ({ count }) => ({ count: count - 1 })\n      stride -= 1\n    }\n  }\n})\n"
  },
  {
    "path": "demo/src/organisms/Items.js",
    "content": "import makeOrganism from '../../../src'\nimport * as loadItemsState from '../state/placeholderAPI'\nimport Items from '../components/Items'\n\n// export default makeOrganism(Items, loadItemsState)\n\nconst baseURL = 'https://jsonplaceholder.typicode.com'\nconst fetchAPI = (path) => fetch(baseURL + path).then(r => r.json())\n\nexport default makeOrganism(Items, {\n  initial: () => ({ items: null }),\n\n  load: function * ({ path }, prevProps) {\n    if (!prevProps || path !== prevProps.path) {\n      yield { items: null } // Clear so 'loading…' text appears\n      yield fetchAPI(path).then(items => ({ items }))\n    }\n  }\n})\n"
  },
  {
    "path": "demo/src/organisms/ItemsChoice.js",
    "content": "import React from 'react'\nimport makeOrganism from '../../../src'\nimport ItemsOrganism from './Items'\n\nexport default makeOrganism(({\n  collection,\n  handlers: {\n    selectPosts,\n    selectPhotos,\n    selectTodos\n  }\n}) => (\n  <div>\n    <div className='h-spaced'>\n      <button onClick={ selectPosts }>Posts</button>\n      <button onClick={ selectPhotos }>Photos</button>\n      <button onClick={ selectTodos }>Todos</button>\n    </div>\n    <ItemsOrganism path={ '/' + collection } collectionName={ collection } />\n  </div>\n), {\n  initial: () => ({ collection: 'posts' }),\n  selectPosts: () => ({ collection: 'posts' }),\n  selectPhotos: () => ({ collection: 'photos' }),\n  selectTodos: () => ({ collection: 'todos' })\n})"
  },
  {
    "path": "demo/src/organisms/Social.js",
    "content": "import React from 'react'\nimport makeMultiCelledOrganism from '../../../src/multi'\nimport extractFromDOM from '../../../src/adjustArgs/extractFromDOM'\nimport PhotosList from '../components/PhotosList'\nimport FriendsList from '../components/FriendsList'\nimport Notifications from '../components/Notifications'\nimport Row from '../components/Row'\n\nimport * as friends from '../state/friends'\nimport * as photos from '../state/photos'\nimport * as selection from '../state/selection'\n\nconst styles = {\n  light: {\n    color: '#111',\n    backgroundColor: '#f6f6f6'\n  },\n  dark: {\n    color: '#f6f6f6',\n    backgroundColor: '#222'\n  }\n}\n\nfunction Social({\n  darkMode = false,\n  cells\n}) {\n  return (\n    <div style={ darkMode ? styles.dark : styles.light }>\n      <Notifications friends={ cells.friends } photos={ cells.photos } />\n      <FriendsList\n        { ...cells.friends }\n        selectedIndex={ cells.selection.selectedFriendIndex }\n        onSelectAtIndex={ cells.selection.handlers.selectFriendAtIndex }\n      />\n      <PhotosList\n        { ...cells.photos }\n        selectedIndex={ cells.selection.selectedPhotoIndex }\n        onSelectAtIndex={ cells.selection.handlers.selectPhotoAtIndex }\n      />\n    </div>\n  )\n}\n\nexport default makeMultiCelledOrganism(Social, {\n  friends,\n  photos,\n  selection\n}, {\n  adjustArgs: extractFromDOM\n})"
  },
  {
    "path": "demo/src/state/counter.js",
    "content": "export const initial = () => ({ count: 0 })\n\nexport const increment = () => ({ count }) => ({ count: count + 1 })\nexport const decrement = () => ({ count }) => ({ count: count - 1 })"
  },
  {
    "path": "demo/src/state/friends.js",
    "content": "export const initial = () => ({\n  friendsList: []\n})\n\nconst convertUserToFriend = (user) => ({\n  name: `${user.first} ${user.last}`\n})\n\nconst fetchRandomFriends = () =>\n  fetch('https://randomapi.com/api/6de6abfedb24f889e0b5f675edc50deb?fmt=raw&sole')\n    .then(res => res.json())\n    .then(users => users.slice(0, 10))\n    .then(users => users.map(convertUserToFriend))\n\nexport const load = async (props, prevProps) => {\n  if (!prevProps) {\n    const newFriends = await fetchRandomFriends()\n    return ({ friendsList }) => ({ friendsList: friendsList.concat(newFriends) })\n  }\n}\n\nexport const addFriend = (props, { name }) => ({ friendsList }) => ({ friendsList: friendsList.concat({ name }) })\n\nexport const addRandomFriend = async ({ handlers }) => {\n  const [ newFriend ] = await fetchRandomFriends()\n  handlers.addFriend(newFriend)\n}"
  },
  {
    "path": "demo/src/state/photos.js",
    "content": "export const initial = () => ({\n  photosList: []\n})\n\nconst fetchRandomPhotoURL = () =>\n  fetch(\n    'https://source.unsplash.com/random/800x600',\n    { method: 'HEAD', cache: 'no-cache' }\n  )\n    .then(res => res.url)\n\nexport const load = async (props, prevProps) => {\n  if (!prevProps) {\n    const url = await fetchRandomPhotoURL()\n    return ({ photosList }) => ({ photosList: photosList.concat({ url }) })\n  }\n}\n\nexport const addPhoto = (props, { url }) => ({ photosList }) => ({ photosList: photosList.concat({ url }) })\n\nexport const addRandomPhoto = async (props) => {\n  const url = await fetchRandomPhotoURL()\n  return addPhoto({}, { url })\n}"
  },
  {
    "path": "demo/src/state/placeholderAPI.js",
    "content": "const baseURL = 'https://jsonplaceholder.typicode.com'\nconst fetchAPI = (path) => fetch(baseURL + path).then(r => r.json())\n\nexport const initial = () => ({ items: null })\n\nexport const load = async ({ path }, prevProps) => {\n  if (!prevProps || path !== prevProps.path) {\n    console.log('load', path)\n    return { items: await fetchAPI(path) }\n  }\n}\n"
  },
  {
    "path": "demo/src/state/selection.js",
    "content": "export const initial = () => ({\n  selectedFriendIndex: null,\n  selectedPhotoIndex: null\n})\n\nexport const selectFriendAtIndex = (props, { index }) => ({ selectedFriendIndex: index })\nexport const selectPhotoAtIndex = (props, { index }) => ({ selectedPhotoIndex: index })\n"
  },
  {
    "path": "nwb.config.js",
    "content": "module.exports = {\n  type: 'react-component',\n  webpack: {\n    hoisting: true\n  },\n  npm: {\n    esModules: true,\n    umd: {\n      global: 'makeOrganism',\n      externals: {\n        'react': 'React'\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-organism\",\n  \"version\": \"0.3.8\",\n  \"description\": \"Separate React state in a dead simple functional way\",\n  \"main\": \"lib/index.js\",\n  \"module\": \"es/index.js\",\n  \"types\": \"src/index.d.ts\",\n  \"files\": [\n    \"css\",\n    \"es\",\n    \"lib\",\n    \"umd\"\n  ],\n  \"scripts\": {\n    \"build\": \"nwb build-react-component\",\n    \"clean\": \"nwb clean-module && nwb clean-demo\",\n    \"dev\": \"nwb serve-react-demo\",\n    \"test\": \"nwb test-react\",\n    \"test:coverage\": \"nwb test-react --coverage\",\n    \"test:watch\": \"nwb test-react --server\",\n    \"now:deploy\": \"yarn run build && cd demo/dist && now deploy\",\n    \"explore-bundle\": \"source-map-explorer\",\n    \"prepublishOnly\": \"npm run test && npm run build\"\n  },\n  \"dependencies\": {\n    \"awareness\": \"^1.1.4\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^15.0.0-0 || ^16.0.0-0\"\n  },\n  \"devDependencies\": {\n    \"nwb\": \"^0.21.5\",\n    \"react\": \"^16.0.0-0\",\n    \"react-dom\": \"^16.0.0-0\",\n    \"source-map-explorer\": \"^1.3.3\"\n  },\n  \"author\": \"\",\n  \"homepage\": \"\",\n  \"license\": \"MIT\",\n  \"repository\": \"\",\n  \"keywords\": [\n    \"react-component\"\n  ]\n}\n"
  },
  {
    "path": "packages/create-react-organism/.gitignore",
    "content": "node_modules"
  },
  {
    "path": "packages/create-react-organism/README.md",
    "content": "# create-react-organism\n\nEasily create [react-organism](https://github.com/RoyalIcing/react-organism) smart components.\n\n## Usage\n\n```sh\nyarn create react-organism CustomName\n\n# or\n\nnpm i -g create-react-organism\ncreate-react-organism CustomName\n```\n\nCreates an **organisms** directory in your project, and a directory for your organism inside there: **[/src]/organisms/CustomName/**\n\nThree files are created inside:\n- **[CustomName].js:** a pure React component that renders the given state as props, as well as call action handlers defined in **state.js**\n- **state.js:** a list of exported functions that handle the progression of state, from its `initial` form, to `load` data in asynchronously, to other action handlers that are called in response to events (e.g. onClick, onChange, etc).\n- **index.js:** connects the pure component and state together and exports it for easy use.\n\nTo use the organism, simply import it:\n\n```javascript\n// pages/example.js\nimport CustomName from '../organisms/CustomName'\n\nexport default () => (\n    <div>\n        <CustomName prop1='one' />\n    </div>\n)\n```"
  },
  {
    "path": "packages/create-react-organism/bin/create-react-organism.js",
    "content": "#!/usr/bin/env node\n\nconst Path = require('path')\nconst FS = require('fs')\nconst Spawn = require('cross-spawn')\nconst { resolve, coroutine, runNode } = require('creed')\nconst _ = require('lodash')\n\nconst accessibleFile = (path) => runNode(FS.access, path).map(() => path).catch(() => null)\n\nconst ensureDir = (path) => runNode(FS.mkdir, path).catch(e => {\n    if (e.code === 'EEXIST') {\n        return\n    }\n\n    throw e\n})\n\nconst installPackage = coroutine(function * installPackage(projectPath, packageName) {\n    const appPackage = require(Path.join(projectPath, 'package.json'))\n    const dependencies = appPackage.dependencies || {}\n    const hasInstalled = !!dependencies[packageName]\n    if (hasInstalled) {\n        return\n    }\n\n    const useYarn = !!(yield accessibleFile(Path.join(projectPath, 'yarn.lock')))\n    const command = useYarn ? 'yarnpkg' : 'npm'\n    let args = useYarn ? ['add'] : ['install', '--save']\n    args.push(packageName)\n    const proc = Spawn.sync(command, args, { stdio: 'inherit' })\n    if (proc.status !== 0) {\n      throw new Error(`\\`${command} ${args.join(' ')}\\` failed with status ${proc.status}`)\n    }\n})\n\nfunction * run([ inputName, ...args ]) {\n    //const fileName = _.kebabCase(inputName)\n    const componentName = _.upperFirst(_.camelCase(inputName))\n\n    let projectPath = process.cwd()\n    let srcPath = yield accessibleFile(Path.resolve(projectPath, 'src'))\n    const codePath = srcPath || projectPath\n\n    // Add react-organism dependency\n    yield installPackage(projectPath, 'react-organism')\n\n    // organisms/\n    const organismsDirPath = Path.resolve(codePath, 'organisms')\n    yield ensureDir(organismsDirPath)\n\n    // organisms/:fileName\n    const organismPath = Path.join(organismsDirPath, componentName)\n    yield ensureDir(organismPath)\n\n    // organisms/:fileName/component.js\n    yield runNode(FS.writeFile, Path.join(organismPath, 'component.js'), makeComponentJS(componentName))\n    // organisms/:fileName/state.js\n    yield runNode(FS.writeFile, Path.join(organismPath, 'state.js'), makeStateJS(componentName))\n    // organisms/:fileName/index.js\n    yield runNode(FS.writeFile, Path.join(organismPath, 'index.js'), makeIndexJS(componentName))\n}\n\n\nfunction makeStateJS(componentName) {\n    return `\nexport const initial = () => ({\n  // TODO: initial state properties\n})\n\nexport const example = (props, ...args) => (prevState) => {\n    // TODO: return changed state\n    return prevState\n}\n`.trim()\n}\n\n\nfunction makeComponentJS(componentName) {\n    return `\nimport React from 'react'\n\nexport default function ${componentName}({\n    // TODO: props\n    handlers: {\n        example\n        // TODO: state handlers\n    }\n}) {\n  return (\n    <div>\n    </div>\n  )\n}\n`.trim()\n}\n\nfunction makeIndexJS(componentName) {\n    return `\nimport makeOrganism from 'react-organism'\nimport ${componentName} from './component'\nimport * as state from './state'\n\nexport default makeOrganism(${componentName}, state)\n`.trim()\n}\n\ncoroutine(run)(process.argv.slice(2))\n    .catch(error => {\n        console.error(error.message)\n    })\n"
  },
  {
    "path": "packages/create-react-organism/package.json",
    "content": "{\n  \"name\": \"create-react-organism\",\n  \"version\": \"0.2.0\",\n  \"description\": \"Tool to easily create react-organism smart components\",\n  \"engines\": {\n    \"node\": \">=6\"\n  },\n  \"bin\": {\n    \"create-react-organism\": \"./bin/create-react-organism.js\"\n  },\n  \"main\": \"index.js\",\n  \"repository\": \"https://github.com/RoyalIcing/react-organism\",\n  \"author\": \"Patrick Smith <patrick@burntcaramel.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"creed\": \"^1.2.1\",\n    \"cross-spawn\": \"^5.1.0\",\n    \"lodash\": \"^4.17.4\"\n  }\n}\n"
  },
  {
    "path": "src/adjustArgs/extractFromDOM.js",
    "content": "import extractValuesFromDOMEvent from 'awareness/lib/extractValuesFromDOMEvent'\n\nexport default function extractFromDOM(args) {\n  if (args[0]) {\n    const values = extractValuesFromDOMEvent(args[0])\n\n    // Place extracted dataset values first, followed by original arguments\n    args = [values].concat(args)\n  }\n\n  return args\n}"
  },
  {
    "path": "src/index.d.ts",
    "content": "declare module 'react-organism' {\n  import React from 'react'\n\n  export interface ReceiverProps<HandlersOut> {\n    handlers: HandlersOut\n  }\n\n  function makeOrganism<Props, State, HandlersIn, HandlersOut>(\n    Pure:\n      | React.ComponentClass<State & ReceiverProps<HandlersOut>>\n      | React.StatelessComponent<State & ReceiverProps<HandlersOut>>,\n    handlersIn: HandlersIn,\n    options?: {\n      onChange: (newState: State) => {}\n      adjustArgs: (args: any[]) => any[]\n    }\n  ): React.ComponentClass<Props>\n\n  export default makeOrganism\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import React, { PureComponent } from 'react'\nimport makeAwareness from 'awareness'\n\n// Returns a new stateful component, given the specified state handlers and a pure component to render with\nexport default (\n  Pure,\n  handlersIn,\n  {\n    onChange,\n    adjustArgs\n  } = {}\n) => class Organism extends PureComponent {\n  static initialStateForProps(props) {\n    return handlersIn.initial(props)\n  }\n\n  get currentState() {\n    return this.props.getState ? this.props.getState() : this.state\n  }\n\n  alterState = (stateChanger) => {\n    // Can either be a plain object or a callback to transform the existing state\n    (this.props.setState || this.setState).call(\n      this,\n      stateChanger,\n      // Call onChange once updated with current version of state\n      onChange ? () => { onChange(this.currentState) } : undefined\n    )\n  }\n\n  awareness = makeAwareness(this.alterState, handlersIn, {\n    getProps: () => this.props,\n    adjustArgs\n  })\n\n  state = this.awareness.state\n\n  componentDidMount() {\n    this.awareness.loadAsync(this.props, null, this.currentState)\n  }\n\n  componentDidUpdate(prevProps, prevState) {\n    this.awareness.loadAsync(this.props, prevProps, this.currentState)\n  }\n\n  render() {\n    // Render the pure component, passing both props and state, plus handlers bundled together\n    return <Pure { ...this.props } { ...this.currentState } handlers={ this.awareness.handlers } />\n  }\n}\n"
  },
  {
    "path": "src/multi.js",
    "content": "import React from 'react'\nimport makeAwareness from 'awareness'\nimport nextFrame from './nextFrame'\n\nfunction cellStateChangerCatchingError(cellKey, stateChanger, errorKey) {\n  return (prevState, props) => {\n    let cellChanges = {}\n    // Check if stateChanger is a function\n    if (typeof(stateChanger) === typeof(stateChanger.call)) {\n      try {\n        // Call state changer\n        cellChanges = stateChanger(prevState[cellKey], props)\n      }\n      // State changer may throw\n      catch (error) {\n        // Store error in state\n        return { [errorKey]: error }\n      }\n    }\n    // Else just an object with changes\n    else {\n      cellChanges = stateChanger\n    }\n    return {\n      [cellKey]: Object.assign({}, prevState[cellKey], cellChanges)\n    }\n  }\n}\n\nfunction processStateChanger(changeState, stateChanger, storeError) {\n  if (!stateChanger) {\n    return;\n  }\n\n  // Check if thenable (i.e. a Promise)\n  if (typeof stateChanger.then === typeof Object.assign) {\n    return stateChanger.then(stateChanger => (\n      stateChanger && changeState(stateChanger)\n    ))\n    .catch(storeError)\n  }\n  // Check if iterator\n  else if (typeof stateChanger.next === typeof Object.assign) {\n    return processIterator(changeState, stateChanger, storeError)\n  }\n  // Otherwise, change state immediately\n  // Required for things like <textarea> onChange to keep cursor in correct position\n  else {\n    changeState(stateChanger)\n  }\n}\n\nfunction processIterator(changeState, iterator, storeError, previousValue) {\n  return Promise.resolve(processStateChanger(changeState, previousValue, storeError)) // Process the previous changer\n  .then(() => nextFrame()) // Wait for next frame\n  .then(() => {\n    const result = iterator.next() // Get the next step from the iterator\n    if (result.done) { // No more iterations remaining\n      return processStateChanger(changeState, result.value, storeError) // Process the changer\n    }\n    else {\n      return processIterator(changeState, iterator, storeError, result.value) // Process the iterator’s following steps\n    }\n  })\n}\n\nexport default function makeMultiOrganism(\n  Parent,\n  cells,\n  {\n    onChange,\n    adjustArgs\n  } = {}\n) {\n  return class OrganismMulticelled extends React.Component {\n    getProps = () => this.props\n\n    cellsAwareness = Object.keys(cells).reduce((out, cellKey) => {\n      const alterState = (stateChanger) => {\n        // Can either be a plain object or a callback to transform the existing state\n        this.setState(\n          (prevState, props) => {\n            const cellChanges = stateChanger(prevState[cellKey])\n            if (cellChanges.loadError || cellChanges.handlerError) {\n              return cellChanges\n            }\n            return {\n              [cellKey]: Object.assign({}, prevState[cellKey], cellChanges)\n            }\n          },\n          // Call onChange once updated with current version of state\n          onChange ? () => { onChange(this.state) } : undefined\n        )\n      }\n\n      out[cellKey] = makeAwareness(alterState, cells[cellKey], {\n        getProps: this.getProps,\n        adjustArgs\n      })\n      return out\n    }, {})\n    \n    state = Object.keys(this.cellsAwareness).reduce((state, cellKey) => {\n      // Grab each cell’s initial value\n      state[cellKey] = this.cellsAwareness[cellKey].state\n      return state\n    }, {\n      loadError: null,\n      handlerError: null\n    })\n\n    changeState(stateChanger) {\n      // Can either be a plain object or a callback to transform the existing state\n      this.setState(\n        stateChanger,\n        // Call onChange once updated with current version of state\n        onChange ? () => { onChange(this.state) } : undefined\n      )\n    }\n\n    loadPromises(nextProps, prevProps) {\n      return Object.keys(cells).map(cellKey => {\n        const handlersIn = cells[cellKey]\n        if (handlersIn.load) {\n          // Wrap in Promise to safely catch any errors thrown by `load`\n          return Promise.resolve(true)\n            .then(() => handlersIn.load(nextProps, prevProps))\n            .then(values => (!!values ? { values, cellKey } : undefined))\n        }\n      })\n          .filter(Boolean) // Filter out cells without .load\n    }\n\n    // Uses `load` handler, if present, to asynchronously load initial state\n    loadAsync(nextProps, prevProps) {\n      this.loadPromises(nextProps, prevProps)\n        .forEach(promise => {\n          promise.then(result => {\n            if (!result) {\n              return\n            }\n            this.changeState(cellStateChangerCatchingError(result.cellKey, result.values, 'loadError'))\n          })\n          .catch(error => this.changeState({ loadError: error }))\n        })\n    }\n\n    // Used by Next.js\n    getInitialProps(props) {\n      return Promise.all(this.loadPromises(props, null))\n        .then(results => results.filter(Boolean)) // Filter out .load that returned nothing\n        .then(results => (\n          results.reduce((initialCellValues, { values, cellKey }) => {\n            initialCellValues[cellKey] = values\n            return initialCellValues\n          }, {})\n        ))\n    }\n\n    componentDidMount() {\n      this.loadAsync(this.props, null)\n    }\n\n    componentWillReceiveProps(nextProps) {\n      this.loadAsync(nextProps, this.props)\n    }\n\n    cellsProxy = Object.keys(cells).reduce((cellsProxy, cellKey) => {\n      const { handlers } = this.cellsAwareness[cellKey]\n\n      Object.defineProperty(cellsProxy, cellKey, {\n        get: () => {\n          // Track which cells are used\n          //this.usedCells[cellKey] = true\n          return Object.assign({}, this.state[cellKey], { handlers })\n        }\n      })\n      return cellsProxy\n    }, {})\n\n    render() {\n      // Render the pure component, passing both props and cells\n      return <Parent { ...this.props } cells={ this.cellsProxy } />\n    }\n  }\n}\n"
  },
  {
    "path": "src/nextFrame.js",
    "content": "export default () => new Promise((resolve) => {\n  window.requestAnimationFrame(resolve)\n})\n"
  },
  {
    "path": "tests/.eslintrc",
    "content": "{\n  \"env\": {\n    \"mocha\": true\n  }\n}\n"
  },
  {
    "path": "tests/extractFromDOM-test.js",
    "content": "import expect from 'expect'\nimport React from 'react'\nimport {render, unmountComponentAtNode} from 'react-dom'\nimport ReactTestUtils from 'react-dom/test-utils'\n\nimport makeOrganism from 'src/'\nimport extractFromDOM from 'src/adjustArgs/extractFromDOM'\n\nconst waitMs = duration => new Promise(resolve => setTimeout(resolve, duration))\n\nfunction PhotosList({\n  photosList,\n  selectedPhotoIndex,\n  handlers: {\n    addPhoto,\n    selectPhotoAtIndex\n  }\n}) {\n  return (\n    <div>\n      <div id='selectionStatus'>\n      {\n        selectedPhotoIndex == null ? (\n          'No photo selected'\n        ) : (\n          `Selected ${selectedPhotoIndex}`\n        )\n      }\n      </div>\n      <div id='photos'>\n      {\n        photosList.length > 0 ? (\n          photosList.map((photo, index) => (\n            <button key={ index }\n              id={`photo-${index}`}\n              data-index_number={ index }\n              onClick={ selectPhotoAtIndex }\n              >\n              <img src={ photo.url } />\n            </button>\n          ))\n        ) : (\n          'No photos'\n        )\n      }\n      </div>\n      <div>\n        <form id='addPhotoForm' data-extract data-reset onSubmit={ addPhoto }>\n          <label>\n            {'URL: '}\n            <input id='urlField' type='url' name='url' />\n          </label>\n          <button id='addPhoto' type='submit' children='Add photo' />\n        </form>\n      </div>\n    </div>\n  )\n}\n\ndescribe('extractFromDOM', () => {\n  let node\n\n  beforeEach(() => {\n    node = document.createElement('div')\n  })\n\n  afterEach(() => {\n    unmountComponentAtNode(node)\n  })\n\n  it('Reads form values', (done) => {\n    const PhotosListOrganism = makeOrganism(PhotosList, {\n      initial: () => ({\n        photosList: [],\n        selectedPhotoIndex: null\n      }),\n      addPhoto: (props, { url }) => ({ photosList }) => ({ photosList: photosList.concat({ url }) }),\n      selectPhotoAtIndex: (props, { index }) => ({ selectedPhotoIndex: index })\n    }, {\n      adjustArgs: extractFromDOM\n    })\n    const $ = (selector) => node.querySelector(selector)\n    render(<PhotosListOrganism />, node, async () => {\n      expect($('#photos').innerHTML).toContain('No photos')\n\n      $('#urlField').value = 'https://via.placeholder.com/350x150'\n      ReactTestUtils.Simulate.change($('#urlField'))\n\n      // Should extract data using named field\n      ReactTestUtils.Simulate.submit($('#addPhotoForm'))\n      await waitMs(10)\n      expect($('#photos').innerHTML).toContain('https://via.placeholder.com/350x150')\n      // Should reset fields if data-reset present\n      expect($('#urlField').value).toBe('')\n\n      // Should extract data- attributes\n      expect($('#selectionStatus').innerHTML).toContain('No photo selected')\n      \n      ReactTestUtils.Simulate.click($('#photo-0'))\n      expect($('#selectionStatus').innerHTML).toContain('Selected 0')\n\n      done()\n    })\n  })\n\n})\n"
  },
  {
    "path": "tests/index-test.js",
    "content": "import expect from 'expect'\nimport React, { Component } from 'react'\nimport {render, unmountComponentAtNode} from 'react-dom'\nimport ReactTestUtils from 'react-dom/test-utils'\n\nimport makeOrganism from 'src/'\n\nconst waitMs = duration => new Promise(resolve => setTimeout(resolve, duration))\n\nconst nextFrame = () => new Promise((resolve) => {\n  window.requestAnimationFrame(resolve)\n})\n\n\nfunction Counter({\n  count,\n  handlers: {\n    increment,\n    decrement,\n    delayedIncrement,\n    delayedIncrementGenerator,\n    doNothing,\n    blowUp,\n    blowUp2,\n    blowUpDelayed,\n    initial,\n    load\n  }\n}) {\n  return (\n    <div>\n      <button id='decrement' onClick={ decrement } children='−' />\n      <span>{ count }</span>\n      <button id='increment' onClick={ increment } children='+' />\n      { delayedIncrement &&\n        <button id='delayedIncrement' onClick={ delayedIncrement } children='+' />\n      }\n      { delayedIncrementGenerator &&\n        <button id='delayedIncrementGenerator' onClick={ delayedIncrementGenerator } children='+' />\n      }\n      { doNothing &&\n        <button id='doNothing' onClick={ doNothing } children='Do Nothing' />\n      }\n      { blowUp &&\n        <button id='blowUp' onClick={ blowUp } children='Blow Up' />\n      }\n      { blowUp2 &&\n        <button id='blowUp2' onClick={ blowUp2 } children='Blow Up 2' />\n      }\n      { blowUpDelayed &&\n        <button id='blowUpDelayed' onClick={ blowUpDelayed } children='Blow Up Delayed' />\n      }\n      <button id='initial' onClick={ initial } children='Reset' />\n      { load &&\n        <button id='reload' onClick={ load } children='Reload' />\n      }\n    </div>\n  )\n}\n\ndescribe('makeOrganism', () => {\n  let node;\n  let latestState;\n  const $ = (selector) => node.querySelector(selector)\n  const promiseRender = (element) => new Promise((resolve) => {\n    render(element, node, resolve)  \n  })\n\n  beforeEach(() => {\n    try {\n    node = document.createElement('div')\n    }\n    catch (error) {\n      console.error('ERRORS', error)\n      throw error\n    }\n  })\n\n  afterEach(() => {\n    unmountComponentAtNode(node)\n  })\n\n  it('Sends click events', async () => {\n    let changeCount = 0\n    const delayWait = 20\n\n    console.log('before makeOrganism')\n    const CounterOrganism = makeOrganism(Counter, {\n      initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n      increment: () => ({ count }) => ({ count: count + 1 }),\n      decrement: () => ({ count }) => ({ count: count - 1 }),\n      delayedIncrement: async () => {\n        await waitMs(delayWait / 2)\n        await waitMs(delayWait / 2)\n        return ({ count }) => ({ count: count + 1 })\n      },\n      delayedIncrementGenerator: function *() {\n        yield waitMs(delayWait / 2)\n        yield waitMs(delayWait / 2)\n        yield ({ count }) => ({ count: count + 1 })\n      },\n      doNothing: () => {},\n      blowUp: () => {\n        throw new Error('Whoops')\n      },\n      blowUp2: () => (prevState) => {\n        throw new Error('Whoops 2')\n      },\n      blowUpDelayed: async () => {\n        await waitMs(delayWait)\n        throw new Error('Whoops Delayed')\n      }\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n    console.log('after makeOrganism')\n\n    await promiseRender(<CounterOrganism initialCount={ 2 } />)\n    expect(node.innerHTML).toContain('2')\n    console.log(node.innerHTML)\n\n    // Click increment\n    ReactTestUtils.Simulate.click($('#increment'))\n    expect(node.innerHTML).toContain('3')\n\n    // Click decrement\n    ReactTestUtils.Simulate.click($('#decrement'))\n    expect(node.innerHTML).toContain('2')\n    expect(changeCount).toBe(2)\n\n    // Click delayedIncrement\n    ReactTestUtils.Simulate.click($('#delayedIncrement'))\n    await waitMs(delayWait + 5)\n    expect(node.innerHTML).toContain('3')\n    expect(changeCount).toBe(3)\n\n    // Click delayedIncrementGenerator\n    ReactTestUtils.Simulate.click($('#delayedIncrementGenerator'))\n    await waitMs(delayWait / 2)\n    await nextFrame()\n    await waitMs(delayWait / 2)\n    await nextFrame()\n    await waitMs(5)\n    await nextFrame()\n    expect(node.innerHTML).toContain('4')\n    expect(changeCount).toBe(4)\n\n    ReactTestUtils.Simulate.click($('#doNothing'))\n    expect(node.innerHTML).toContain('4')\n    expect(changeCount).toBe(4)\n\n    // Click blowUp\n    ReactTestUtils.Simulate.click($('#blowUp'))\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops')\n\n    // Click blowUp2\n    ReactTestUtils.Simulate.click($('#blowUp2'))\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops 2')\n\n    // Click blowUpDelayed\n    ReactTestUtils.Simulate.click($('#blowUpDelayed'))\n    await waitMs(delayWait + 5)\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops Delayed')\n\n    expect(changeCount).toBe(7)\n  })\n\n  it('Calls load handler', async () => {\n    let changeCount = 0\n    let latestState;\n    const loadWait = 35\n\n    const CounterOrganism = makeOrganism(Counter, {\n      initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n      load: async ({ loadedCount }, prevProps) => {\n        if (!prevProps || loadedCount !== prevProps.loadedCount) {\n          await waitMs(loadWait)\n          const count = loadedCount * 2 // Multiply to be sure we are using this loaded value\n          if (Number.isNaN(count)) {\n            throw new Error('Loaded count is invalid')\n          }\n          return { count }\n        }\n      },\n      increment: () => ({ count }) => ({ count: count + 1 }),\n      decrement: () => ({ count }) => ({ count: count - 1 })\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n\n    await promiseRender(<CounterOrganism initialCount={ 2 } loadedCount={ 7 } />)\n    expect(node.innerHTML).toContain('2')\n\n    // Click increment\n    ReactTestUtils.Simulate.click($('#increment'))\n    expect(node.innerHTML).toContain('3')\n\n    // Click decrement\n    ReactTestUtils.Simulate.click($('#decrement'))\n    expect(node.innerHTML).toContain('2')\n\n    expect(changeCount).toBe(2)\n\n    await waitMs(loadWait + 5)\n    expect(node.innerHTML).toContain(14)\n    expect(changeCount).toBe(3)\n\n    await promiseRender(<CounterOrganism initialCount={ 22 } loadedCount={ 7 } />)\n    expect(node.innerHTML).toContain(14)\n    expect(changeCount).toBe(3)\n\n    await promiseRender(<CounterOrganism initialCount={ 22 } loadedCount={ 9 } />)\n    await waitMs(loadWait + 5)\n    expect(node.innerHTML).toContain(18)\n    expect(changeCount).toBe(4)\n\n    // Click reload\n    ReactTestUtils.Simulate.click($('#reload'))\n    await waitMs(loadWait + 5)\n    expect(node.innerHTML).toContain(18)\n    expect(changeCount).toBe(5)\n\n    // Load error\n    promiseRender(<CounterOrganism initialCount={ 22 } loadedCount='Not a number' />)\n    await waitMs(loadWait + 5)\n    expect(latestState.loadError).toExist()\n    expect(changeCount).toBe(6)\n  })\n\n  it('Supports getState/setState props', async () => {\n    let changeCount = 0\n    const delayWait = 20\n\n    const CounterOrganism = makeOrganism(Counter, {\n      initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n      increment: () => ({ count }) => ({ count: count + 1 }),\n      decrement: () => ({ count }) => ({ count: count - 1 }),\n      delayedIncrement: async () => {\n        await waitMs(delayWait / 2)\n        await waitMs(delayWait / 2)\n        return ({ count }) => ({ count: count + 1 })\n      },\n      delayedIncrementGenerator: function *() {\n        yield waitMs(delayWait / 2)\n        yield waitMs(delayWait / 2)\n        yield ({ count }) => ({ count: count + 1 })\n      },\n      doNothing: () => {},\n      blowUp: () => {\n        throw new Error('Whoops')\n      },\n      blowUp2: () => (prevState) => {\n        throw new Error('Whoops 2')\n      },\n      blowUpDelayed: async () => {\n        await waitMs(delayWait)\n        throw new Error('Whoops Delayed')\n      }\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n\n    class Wrapper extends Component {\n      state = CounterOrganism.initialStateForProps(this.props)\n\n      render() {\n        return <CounterOrganism\n          getState={ () => this.state }\n          setState={ this.setState.bind(this) }\n        />\n      }\n    }\n\n    await promiseRender(<Wrapper initialCount={ 2 } />)\n    expect(node.innerHTML).toContain('2')\n    console.log(node.innerHTML)\n\n    // Click increment\n    ReactTestUtils.Simulate.click($('#increment'))\n    expect(node.innerHTML).toContain('3')\n\n    // Click decrement\n    ReactTestUtils.Simulate.click($('#decrement'))\n    expect(node.innerHTML).toContain('2')\n    expect(changeCount).toBe(2)\n\n    // Click delayedIncrement\n    ReactTestUtils.Simulate.click($('#delayedIncrement'))\n    await waitMs(delayWait + 5)\n    expect(node.innerHTML).toContain('3')\n    expect(changeCount).toBe(3)\n  })\n\n})\n"
  },
  {
    "path": "tests/multi-test.js",
    "content": "import expect from 'expect'\nimport React from 'react'\nimport {render, unmountComponentAtNode} from 'react-dom'\nimport ReactTestUtils from 'react-dom/test-utils'\n\nimport makeMulticelledOrganism from 'src/multi'\n\nconst waitMs = duration => new Promise(resolve => setTimeout(resolve, duration))\n\nconst nextFrame = () => new Promise((resolve) => {\n  window.requestAnimationFrame(resolve)\n})\n\nfunction Counter({\n  id,\n  count,\n  title,\n  handlers: {\n    increment,\n    decrement,\n    delayedIncrement,\n    delayedIncrementGenerator,\n    doNothing,\n    blowUp,\n    blowUp2,\n    blowUpDelayed,\n    initial,\n    load,\n    changeTitle,\n    uppercaseTitle,\n    makeTitleHeading\n  }\n}) {\n  return (\n    <div>\n      <h2 id={`${id}-title`}>{ title }</h2>\n      <button id={`${id}-decrement`} onClick={ decrement } children='−' />\n      <span id={`${id}-currentCount`}>{ id }: { count }</span>\n      <button id={`${id}-increment`} onClick={ increment } children='+' />\n      { delayedIncrement &&\n        <button id={`${id}-delayedIncrement`} onClick={ delayedIncrement } children='+' />\n      }\n      { delayedIncrementGenerator &&\n        <button id={`${id}-delayedIncrementGenerator`} onClick={ delayedIncrementGenerator } children='+' />\n      }\n      { doNothing &&\n        <button id={`${id}-doNothing`} onClick={ doNothing } children='Do Nothing' />\n      }\n      { blowUp &&\n        <button id={`${id}-blowUp`} onClick={ blowUp } children='Blow Up' />\n      }\n      { blowUp2 &&\n        <button id={`${id}-blowUp2`} onClick={ blowUp2 } children='Blow Up 2' />\n      }\n      { blowUpDelayed &&\n        <button id={`${id}-blowUpDelayed`} onClick={ blowUpDelayed } children='Blow Up Delayed' />\n      }\n      <button id={`${id}-initial`} onClick={ initial } children='Reset' />\n      { load &&\n        <button id='reload' onClick={ load } children='Reload' />\n      }\n\n      <input id={`${id}-changeTitle`} onChange={ changeTitle } />\n      <button id={`${id}-uppercaseTitle`} onClick={ uppercaseTitle } children='uppercaseTitle' />\n      <button id={`${id}-makeTitleHeading`} onClick={ makeTitleHeading } children='makeTitleHeading' />\n    </div>\n  )\n}\n\nconst counterModel = {\n  initial: ({ initialCount = 0 }) => ({ count: initialCount }),\n  increment: () => ({ count }) => ({ count: count + 1 }),\n  decrement: () => ({ count }) => ({ count: count - 1 }),\n  delayedIncrement: async () => {\n    await waitMs(delayWait)\n    return ({ count }) => ({ count: count + 1 })\n  },\n  delayedIncrementGenerator: function *() {\n    yield waitMs(delayWait / 2)\n    yield waitMs(delayWait / 2)\n    yield ({ count }) => ({ count: count + 1 })\n  },\n  doNothing: () => {},\n  blowUp: () => {\n    throw new Error('Whoops')\n  },\n  blowUp2: () => (prevState) => {\n    throw new Error('Whoops 2')\n  },\n  blowUpDelayed: async () => {\n    await waitMs(delayWait)\n    throw new Error('Whoops Delayed')\n  }\n}\n\nconst loadWait = 35\nconst delayWait = 20\nconst counterLoadModel = {\n  initial: ({ initialCount = 0 }) => ({\n    count: initialCount,\n    title: 'Counter'\n  }),\n  load: async ({ loadedCount }, prevProps) => {\n    if (!prevProps || loadedCount !== prevProps.loadedCount) {\n      await waitMs(loadWait)\n      const count = loadedCount * 2 // Multiply to be sure we are using this loaded value\n      if (Number.isNaN(count)) {\n        throw new Error('Loaded count is invalid')\n      }\n      return { count }\n    }\n  },\n  increment: () => ({ count }) => ({ count: count + 1 }),\n  decrement: () => ({ count }) => ({ count: count - 1 }),\n  changeTitle: (props, { value }) => ({ title: value }),\n  uppercaseTitle: () => ({ title }) => ({ title: title.toUpperCase() }),\n  makeTitleHeading: () => ({ title: 'Heading' })\n}\n\ndescribe('makeMulticelledOrganism', () => {\n  let node;\n  const $ = (selector) => node.querySelector(selector)\n  let promiseRender;\n\n  beforeEach(() => {\n    node = document.createElement('div')\n    promiseRender = (element) => new Promise((resolve) => {\n      render(element, node, resolve)\n    })\n  })\n\n  afterEach(() => {\n    unmountComponentAtNode(node)\n  })\n\n  it('Sends click events', async () => {\n    let changeCount = 0\n    let latestState;\n\n    const Organism = makeMulticelledOrganism(({\n      cells: {\n        counterA,\n        counterB\n      }\n    }) => (\n      <div>\n        <Counter id='a' { ...counterA } />\n        <Counter id='b' { ...counterB } />\n      </div>\n    ), {\n      counterA: counterModel,\n      counterB: counterModel\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n\n    await promiseRender(<Organism initialCount={ 2 } />)\n    const $aCurrentCount = $('#a-currentCount')\n    const $bCurrentCount = $('#b-currentCount')\n    expect($aCurrentCount.textContent).toBe('a: 2')\n    expect($bCurrentCount.textContent).toBe('b: 2')\n\n    // Click a increment\n    ReactTestUtils.Simulate.click($('#a-increment'))\n    expect($aCurrentCount.textContent).toBe('a: 3')\n    expect($bCurrentCount.textContent).toBe('b: 2')\n\n    // Click a decrement\n    ReactTestUtils.Simulate.click($('#a-decrement'))\n    expect($aCurrentCount.textContent).toBe('a: 2')\n    expect($bCurrentCount.textContent).toBe('b: 2')\n\n    // Click b decrement\n    ReactTestUtils.Simulate.click($('#b-decrement'))\n    expect($aCurrentCount.textContent).toBe('a: 2')\n    expect($bCurrentCount.textContent).toBe('b: 1')\n    expect(changeCount).toBe(3)\n\n    // Click delayedIncrement\n    ReactTestUtils.Simulate.click($('#a-delayedIncrement'))\n    await waitMs(delayWait + 5)\n    expect($aCurrentCount.textContent).toBe('a: 3')\n    expect($bCurrentCount.textContent).toBe('b: 1')\n    expect(changeCount).toBe(4)\n\n    // Click delayedIncrementGenerator\n    ReactTestUtils.Simulate.click($('#a-delayedIncrementGenerator'))\n    await waitMs(delayWait / 2)\n    await nextFrame()\n    await waitMs(delayWait / 2)\n    await nextFrame()\n    await waitMs(5)\n    expect($aCurrentCount.textContent).toBe('a: 4')\n    expect($bCurrentCount.textContent).toBe('b: 1')\n    expect(changeCount).toBe(5)\n\n    ReactTestUtils.Simulate.click($('#b-doNothing'))\n    expect($aCurrentCount.textContent).toBe('a: 4')\n    expect($bCurrentCount.textContent).toBe('b: 1')\n    expect(changeCount).toBe(5)\n\n    // Click blowUp\n    ReactTestUtils.Simulate.click($('#a-blowUp'))\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops')\n\n    // Click blowUp2\n    ReactTestUtils.Simulate.click($('#b-blowUp2'))\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops 2')\n\n    // Click blowUpDelayed\n    ReactTestUtils.Simulate.click($('#a-blowUpDelayed'))\n    await waitMs(delayWait + 5)\n    expect(latestState.handlerError).toExist()\n    expect(latestState.handlerError.message).toBe('Whoops Delayed')\n  })\n\n  it('Calls load handler', async () => {\n    let changeCount = 0\n    let latestState;\n    const loadWait = 35\n\n    const Organism = makeMulticelledOrganism(({\n      cells: {\n        counterA,\n        counterB\n      }\n    }) => (\n      <div>\n        <Counter id='a' { ...counterA } />\n        <Counter id='b' { ...counterB } />\n      </div>\n    ), {\n      counterA: counterLoadModel,\n      counterB: counterLoadModel\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n\n    await promiseRender(<Organism initialCount={ 2 } loadedCount={ 7 } />)\n    const $aCurrentCount = $('#a-currentCount')\n    const $aTitle = $('#a-title')\n\n    expect($aCurrentCount.textContent).toContain('2')\n\n    // Click increment\n    ReactTestUtils.Simulate.click($('#a-increment'))\n    expect($aCurrentCount.textContent).toContain('3')\n\n    // Click decrement\n    ReactTestUtils.Simulate.click($('#a-decrement'))\n    expect($aCurrentCount.textContent).toContain('2')\n    expect(changeCount).toBe(2)\n\n    await waitMs(loadWait + 5)\n    // Loaded\n    expect($aCurrentCount.textContent).toContain('14')\n    expect(changeCount).toBe(4) // Both cells loaded, so change count increases by 2\n\n    await promiseRender(<Organism initialCount={ 22 } loadedCount={ 7 } />)\n    // Takes some time to load, so shouldn’t have changed yet\n    expect($aCurrentCount.textContent).toContain('14')\n    expect(changeCount).toBe(4)\n\n    await promiseRender(<Organism initialCount={ 22 } loadedCount={ 9 } />)\n    await waitMs(loadWait + 5)\n    // Loaded from new props\n    expect($aCurrentCount.textContent).toContain('18')\n    expect(changeCount).toBe(6)\n\n    expect($aTitle.textContent).toBe('Counter')\n\n    ReactTestUtils.Simulate.click($('#a-uppercaseTitle'))\n    expect($aTitle.textContent).toBe('COUNTER')\n    expect(changeCount).toBe(7)\n\n    ReactTestUtils.Simulate.click($('#a-makeTitleHeading'))\n    expect($aTitle.textContent).toBe('Heading')\n    expect(changeCount).toBe(8)\n\n    // Click reload\n    ReactTestUtils.Simulate.click($('#reload'))\n    await waitMs(loadWait + 5)\n    expect($aCurrentCount.textContent).toContain('18')\n    expect(changeCount).toBe(9)\n\n    // Load error\n    await promiseRender(<Organism initialCount={ 22 } loadedCount='Not a number' />)\n    await waitMs(loadWait + 5)\n    expect(latestState.loadError).toExist()\n    expect(changeCount).toBe(11)\n  })\n\n  it('getInitialProps()', async () => {\n    let changeCount = 0\n    let latestState;\n    const loadWait = 35\n\n    const Organism = makeMulticelledOrganism(({\n      cells: {\n        counterA,\n        counterB\n      }\n    }) => (\n      <div>\n        <Counter id='a' { ...counterA } />\n        <Counter id='b' { ...counterB } />\n      </div>\n    ), {\n      counterA: counterLoadModel,\n      counterB: counterLoadModel\n    }, {\n      onChange(state) {\n        latestState = state\n        changeCount++\n      }\n    })\n\n    const element = <Organism initialCount={ 2 } loadedCount={ 7 } />\n    const instance = new Organism(element.props)\n\n    const initialProps = await instance.getInitialProps(element.props)\n    expect(initialProps).toEqual({\n      counterA: { count: 14 },\n      counterB: { count: 14 }\n    })\n  })\n\n})\n"
  },
  {
    "path": "umd/react-organism.js",
    "content": "/*!\n * react-organism v0.3.6\n * MIT Licensed\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"react\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"makeOrganism\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"makeOrganism\"] = factory(root[\"React\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(1);\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(2);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_awareness__ = __webpack_require__(3);\nvar _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; };\n\nvar _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; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n\n\n\n// Returns a new stateful component, given the specified state handlers and a pure component to render with\n/* harmony default export */ __webpack_exports__[\"default\"] = (function (Pure, handlersIn) {\n  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n      onChange = _ref.onChange,\n      adjustArgs = _ref.adjustArgs;\n\n  return function (_PureComponent) {\n    _inherits(Organism, _PureComponent);\n\n    function Organism() {\n      var _temp, _this, _ret;\n\n      _classCallCheck(this, Organism);\n\n      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n        args[_key] = arguments[_key];\n      }\n\n      return _ret = (_temp = (_this = _possibleConstructorReturn(this, _PureComponent.call.apply(_PureComponent, [this].concat(args))), _this), _this.alterState = function (stateChanger) {\n        // Can either be a plain object or a callback to transform the existing state\n        (_this.props.setState || _this.setState).call(_this, stateChanger,\n        // Call onChange once updated with current version of state\n        onChange ? function () {\n          onChange(_this.currentState);\n        } : undefined);\n      }, _this.awareness = Object(__WEBPACK_IMPORTED_MODULE_1_awareness__[\"a\" /* default */])(_this.alterState, handlersIn, {\n        getProps: function getProps() {\n          return _this.props;\n        },\n        adjustArgs: adjustArgs\n      }), _this.state = _this.awareness.state, _temp), _possibleConstructorReturn(_this, _ret);\n    }\n\n    Organism.initialStateForProps = function initialStateForProps(props) {\n      return handlersIn.initial(props);\n    };\n\n    Organism.prototype.componentDidMount = function componentDidMount() {\n      this.awareness.loadAsync(this.props, null, this.currentState);\n    };\n\n    Organism.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {\n      this.awareness.loadAsync(nextProps, this.props, this.currentState);\n    };\n\n    Organism.prototype.render = function render() {\n      // Render the pure component, passing both props and state, plus handlers bundled together\n      return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(Pure, _extends({}, this.props, this.currentState, { handlers: this.awareness.handlers }));\n    };\n\n    _createClass(Organism, [{\n      key: 'currentState',\n      get: function get() {\n        return this.props.getState ? this.props.getState() : this.state;\n      }\n    }]);\n\n    return Organism;\n  }(__WEBPACK_IMPORTED_MODULE_0_react__[\"PureComponent\"]);\n});\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE_2__;\n\n/***/ }),\n/* 3 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export callHandler */\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\nvar nextFrame = function nextFrame() {\n  return new Promise(function (resolve) {\n    window.requestAnimationFrame(resolve);\n  });\n};\n\nfunction stateChangerCatchingError(stateChanger, transformError) {\n  return function (prevState, props) {\n    // Check if stateChanger is a function\n    if ((typeof stateChanger === 'undefined' ? 'undefined' : _typeof(stateChanger)) === _typeof(stateChanger.call)) {\n      try {\n        // Call state changer\n        return stateChanger(prevState, props);\n      }\n      // State changer may throw\n      catch (error) {\n        // Store error in state\n        return transformError(error);\n      }\n    }\n    // Else just an object with changes\n    else {\n        return stateChanger;\n      }\n  };\n}\n\nfunction processStateChanger(changeState, stateChanger, storeError) {\n  if (!stateChanger) {\n    return;\n  }\n\n  // Check if thenable (i.e. a Promise)\n  if (_typeof(stateChanger.then) === _typeof(Object.assign)) {\n    return stateChanger.then(function (stateChanger) {\n      return stateChanger && changeState(stateChanger);\n    }).catch(storeError);\n  }\n  // Check if iterator\n  else if (_typeof(stateChanger.next) === _typeof(Object.assign)) {\n      return processIterator(changeState, stateChanger, storeError);\n    }\n    // Otherwise, change state immediately\n    // Required for things like <textarea> onChange to keep cursor in correct position\n    else {\n        changeState(stateChanger);\n      }\n}\n\nfunction processIterator(changeState, iterator, storeError, previousValue) {\n  return Promise.resolve(processStateChanger(changeState, previousValue, storeError)) // Process the previous changer\n  .then(function () {\n    return nextFrame();\n  }) // Wait for next frame\n  .then(function () {\n    var result = iterator.next(); // Get the next step from the iterator\n    if (result.done) {\n      // No more iterations remaining\n      return processStateChanger(changeState, result.value, storeError); // Process the changer\n    } else {\n      return processIterator(changeState, iterator, storeError, result.value); // Process the iterator’s following steps\n    }\n  });\n}\n\nfunction callHandler(handler, transformError, args, alterState) {\n  if ((typeof transformError === 'undefined' ? 'undefined' : _typeof(transformError)) === _typeof('')) {\n    var errorKey = transformError;\n    transformError = function transformError(error) {\n      var _ref;\n\n      return _ref = {}, _ref[errorKey] = error, _ref;\n    };\n  }\n\n  var storeError = function storeError(error) {\n    alterState(function () {\n      return transformError(error);\n    });\n  };\n  // Call handler function, props first, then rest of args\n  try {\n    var changeState = function changeState(stateChanger) {\n      alterState(stateChangerCatchingError(stateChanger, transformError));\n    };\n    var result = handler.apply(null, args);\n    // Can return multiple state changers, ensure array, and then loop through\n    [].concat(result).forEach(function (stateChanger) {\n      processStateChanger(changeState, stateChanger, storeError);\n    });\n  }\n  // Catch error within handler’s (first) function\n  catch (error) {\n    storeError(error);\n  }\n}\n\nvar defaultTransformErrorForKey = function defaultTransformErrorForKey(key) {\n  return function (error) {\n    var _ref2;\n\n    var stateKey = (key === 'load' ? 'load' : 'handler') + 'Error';\n    return _ref2 = {}, _ref2[stateKey] = error, _ref2;\n  };\n};\n\n// Returns a new stateful component, given the specified state handlers and a pure component to render with\n/* harmony default export */ __webpack_exports__[\"a\"] = (function (alterState, handlersIn) {\n  var _ref3 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n      _ref3$getProps = _ref3.getProps,\n      getProps = _ref3$getProps === undefined ? function () {\n    return {};\n  } : _ref3$getProps,\n      _ref3$transformErrorF = _ref3.transformErrorForKey,\n      transformErrorForKey = _ref3$transformErrorF === undefined ? defaultTransformErrorForKey : _ref3$transformErrorF,\n      adjustArgs = _ref3.adjustArgs;\n\n  var state = Object.assign({\n    loadError: null,\n    handlerError: null\n  }, handlersIn.initial(getProps()));\n\n  // Uses `load` handler, if present, to asynchronously load initial state\n  function loadAsync() {\n    if (handlersIn.load) {\n      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n        args[_key] = arguments[_key];\n      }\n\n      callHandler(handlersIn.load, transformErrorForKey('load'), args, alterState);\n    }\n  }\n\n  var handlers = Object.keys(handlersIn).reduce(function (out, key) {\n    // Special case for `load` handler to reload fresh\n    if (key === 'load') {\n      out.load = function () {\n        loadAsync(getProps(), null);\n      };\n      return out;\n    }\n\n    out[key] = function () {\n      for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n        args[_key2] = arguments[_key2];\n      }\n\n      if (adjustArgs) {\n        args = adjustArgs(args);\n      }\n\n      callHandler(handlersIn[key], transformErrorForKey(key), [Object.assign({}, getProps(), { handlers: handlers })].concat(args), alterState);\n    };\n    return out;\n  }, {});\n\n  return {\n    state: state,\n    loadAsync: loadAsync,\n    handlers: handlers\n  };\n});\n\n/***/ })\n/******/ ]);\n});"
  }
]