Full Code of chenglou/react-motion for AI

master 9e3ce95bacaa cached
68 files
183.5 KB
53.2k tokens
162 symbols
1 requests
Download .txt
Repository: chenglou/react-motion
Branch: master
Commit: 9e3ce95bacaa
Files: 68
Total size: 183.5 KB

Directory structure:
gitextract_zo4f_ak9/

├── .babelrc
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .npmignore
├── .size-snapshot.json
├── .travis.yml
├── AUTHORS
├── HISTORY.md
├── LICENSE
├── README.md
├── bower.json
├── demos/
│   ├── README.md
│   ├── demo0-simple-transition/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo1-chat-heads/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo2-draggable-balls/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo3-todomvc-list-transition/
│   │   ├── Demo.jsx
│   │   ├── index.css
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo4-photo-gallery/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo5-spring-parameters-chooser/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo7-water-ripples/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   └── demo8-draggable-list/
│       ├── Demo.jsx
│       ├── index.html
│       └── index.jsx
├── karma.conf.js
├── package.json
├── rollup.config.js
├── server.js
├── src/
│   ├── Motion.js
│   ├── StaggeredMotion.js
│   ├── TransitionMotion.js
│   ├── Types.js
│   ├── mapToZero.js
│   ├── mergeDiff.js
│   ├── presets.js
│   ├── react-motion.js
│   ├── reorderKeys.js
│   ├── shouldStopAnimation.js
│   ├── spring.js
│   ├── stepper.js
│   └── stripStyle.js
├── test/
│   ├── Motion-test.js
│   ├── StaggeredMotion-test.js
│   ├── TransitionMotion-test.js
│   ├── createMockRaf.js
│   ├── index.js
│   ├── integration/
│   │   ├── README.md
│   │   ├── bower.html
│   │   ├── bower.json
│   │   └── package.json
│   ├── mergeDiff-test.js
│   └── stripStyle-test.js
└── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "presets": [
    ["@babel/env", { "modules": "commonjs", "loose": true }],
    "@babel/flow",
    "@babel/react"
  ],
  "plugins": [
    ["@babel/proposal-class-properties", { "loose": true }],
    ["transform-react-remove-prop-types", { "mode": "unsafe-wrap" }]
  ],
  "env": {
    "test": {
      "plugins": [
        "@babel/transform-modules-commonjs"
      ]
    }
  }
}


================================================
FILE: .eslintignore
================================================
build
coverage
lib
node_modules
**/*/all.js
webpack.*.js
server.js
karma.*.js
test/integration
demos/demo6/babel.js
demos/*/Demo.jsx


================================================
FILE: .eslintrc
================================================
{
  "parser": "babel-eslint",
  "extends": ["airbnb", "prettier"],
  "env": {
    "browser": true,
    "es6": true,
    "jasmine": true
  },
  "rules": {
    "eqeqeq": [2, "allow-null"],
    "id-length": 0,
    "no-console": 0, // use it for warnings
    "no-nested-ternary": 0,
    "prefer-const": 0,
    "no-multiple-empty-lines": 0,
    "no-useless-escape": 0,
    "no-else-return": 0,
    "comma-dangle": 0,
    "lines-between-class-members": 0,
    "indent": 0,
    "operator-linebreak": 0,
    "object-curly-newline": 0,
    "function-paren-newline": 0,
    "prefer-destructuring": 0,
    "camelcase": ["error", {"allow": ["^UNSAFE_"]}],

    "react/jsx-wrap-multilines": 0,
    "react/jsx-one-expression-per-line": 0,
    "react/no-unused-state": 0,
    "react/require-default-props": 0,
    "react/destructuring-assignment": 0,
    "react/no-did-mount-set-state": 2,
    "react/no-multi-comp": 0,
    "react/jsx-boolean-value": [2, "always"],
    "react/sort-comp": [
      2, {
        "order": [
          "displayName",
          "propTypes",
          "contextTypes",
          "childContextTypes",
          "mixins",
          "statics",
          "defaultProps",
          "getDefaultProps",
          "getInitialState",
          "getChildContext",
          "componentWillMount",
          "UNSAFE_componentWillMount",
          "componentDidMount",
          "componentWillReceiveProps",
          "UNSAFE_componentWillReceiveProps",
          "shouldComponentUpdate",
          "componentWillUpdate",
          "UNSAFE_componentWillUpdate",
          "componentDidUpdate",
          "componentWillUnmount",
          "/^on.+$/",
          "/^get.+$/",
          "/^render.+$/",
          "/^.+$/", // All other methods go here
          "render"
        ]
      }
    ],

    "max-len": 0,
    "no-mixed-operators": 0,
    "no-continue": 0,
    "no-restricted-syntax": 0,
    "no-plusplus": 0,
    "no-confusing-arrow": 0,
    "arrow-parens": 0,
    "arrow-body-style": 0,
    "react/jsx-indent": 0,
    "react/jsx-indent-props": 0,
    "react/jsx-closing-bracket-location": 0,
    "react/prefer-es6-class": 0,
    "react/jsx-filename-extension": 0,
    "react/prefer-stateless-function": 0,
    "object-curly-spacing": 0,
    "import/imports-first": 0,
    "import/no-unresolved": 0,
    "import/no-extraneous-dependencies": 0,
    "import/order": 0,
    "import/no-webpack-loader-syntax": 0,
  }
}


================================================
FILE: .flowconfig
================================================
[ignore]
.*/node_modules/fbjs/lib/PromiseMap.js
.*/node_modules/fbjs/lib/fetchWithRetries.js
.*/node_modules/fbjs/lib/Deferred.js.flow
.*/node_modules/fbjs/lib/equalsSet.js.flow
.*/node_modules/fbjs/lib/shallowEqual.js.flow
.*/node_modules/fbjs/lib/someSet.js.flow
.*/node_modules/fbjs/lib/everySet.js.flow
.*/node_modules/fbjs/lib/UnicodeBidi.js.flow
.*/node_modules/fbjs/lib/UnicodeBidiService.js.flow
.*/node_modules/kefir/kefir.js.flow
.*/node_modules/kefir/dist/kefir.js.flow
.*/test/.*
.*/node_modules/@webassemblyjs/.*
.*/node_modules/eslint-plugin-jsx-a11y/.*
.*/node_modules/rollup-plugin-size-snapshot/.*
.*/node_modules/babel-plugin-transform-react-remove-prop-types

[include]

[libs]

[options]


================================================
FILE: .gitignore
================================================
logs
*.log

pids
*.pid
*.seed

coverage
node_modules
bower_components

.DS_Store

/demos/**/all.*
/build/
/lib/


================================================
FILE: .npmignore
================================================
/.*

/bower_components/

/coverage/
/demos/
/test/

/karma.conf.js
/webpack.*
/server.js

# sublime
/*.sublime-project
/*.sublime-workspace

/rollup.config.js


================================================
FILE: .size-snapshot.json
================================================
{
  "build/react-motion.js": {
    "bundled": 77059,
    "minified": 22596,
    "gzipped": 6616
  },
  "build/react-motion.min.js": {
    "bundled": 52481,
    "minified": 15210,
    "gzipped": 4446
  },
  "lib/react-motion.esm.js": {
    "bundled": 43290,
    "minified": 14594,
    "gzipped": 3583,
    "treeshaked": {
      "rollup": {
        "code": 6381,
        "import_statements": 196
      },
      "webpack": {
        "code": 7588
      }
    }
  }
}


================================================
FILE: .travis.yml
================================================
language: node_js

node_js:
  - 10

script:
 - npm run -s lint
 - npm run -s flow_check
 - npm run -s test:travis


================================================
FILE: AUTHORS
================================================
Adrian le Bas
Amadeus Junqueira
Benjamin San Souci
Bishop Zareh
Brenton Simpson
Cesar Andreu
Cheng Lou
Dan Abramov
Daniel Dunderfelt
Dustan Kasten
Frederick Fogerty
Gaëtan Renaudeau
Google, Inc.
Henry Zhu
Ivan Starkov
Jeroen van Aert
Jesper Petersson
Jevgeni Geimanen
Joe Lencioni
John Amiah Ford
Jon Lebensold
Justin Morris
Kyle Mathews
Ludovico Fischer
Michael J Hoffman
Mirko Mariani
Neil Kistner
Nik Butenko
Nikhil Baradwaj
Olivier Tassinari
Paolo Moretti
Raymond Zhou
Robert Haritonov
Sorin Iclanzan
Stefan Dombrowski
Stephen J. Collings
Sundeep Malladi
Sunil Pai
Travis Arnold
Wilfred Denton


================================================
FILE: HISTORY.md
================================================
Legend:
- [B]: Breaking
- [F]: Fix
- [I]: Improvement

### 0.5.1 (August 28th 2017)
- [F] New flow definitions, fixes children typing.

### 0.5.0 (April 26th 2017)
- [B] Dropping support for older React. Currently supported versions are `^0.14.9` || `^15.3.0`
- [I] Upgraded all React components to use ES6 classes
- [I] Replace React.PropTypes with prop-types package

### 0.4.8 (April 17th 2017)

- [I] Externalize stripStyle #452 by @bearcott
- [I] Migrated deprecated React.PropTypes and React.createClass #446 by @Andarist
- [F] Fix link to TypeScript types #443 by @pshrmn
- [F] Refactored demo and fixed flow check errors #435 by @therewillbecode
- [F] Fix broken link #430 by @codler
- [F] Unmounted component setState fix #420 by @alleycat-at-git

### 0.4.7 (December 15th 2016)
- [I] `didLeave` for `TransitionMotion`! Please check the README for more.

### 0.4.4 (June 4th 2016)
- [F] Small fix to component unmounting bug (https://github.com/chenglou/react-motion/commit/49ea396041b0031b95f4941cc7efce200fcca454). It's not clear why this is erroring, but people want the temp fix.

### 0.4.3 (April 19th 2016)
- [F] `TransitionMotion` `styles` function not being passed `defaultStyles` value upon first call. #296
- [I] `onRest` callback for `Motion`!

### 0.4.2 (January 30th 2016)
- [F] `TransitionMotion` keys merging bug. #264
- [F] `TransitionMotion` rare stale read bug. [https://github.com/chenglou/react-motion/commit/f20dc1b9c8de7b387927b24afdb73e0a5ea0d0a6](https://github.com/chenglou/react-motion/commit/f20dc1b9c8de7b387927b24afdb73e0a5ea0d0a6)

### 0.4.1 (January 26th 2016)
- [F] Made a mistake while publishing the bower package; fixed.

### 0.4.0 (January 26th 2016)
- [B] `spring` helper's format has changed from `spring(10, [120, 12])` to `spring(10, {stiffness: 120, damping: 12})`.
- [B] `style`, `styles` and `styles` of the three respective components now only accept either a number to interpolate, or a `spring` configuration to interpolate. Previously, it accepted (and ignored) random key/value pairs mixed in, such as `{x: spring(0), y: 'helloWorld'}`. `y` Doesn't belong there and should be placed elsewhere, e.g. directly on the (actual react) style of the component you're assigning the interpolating values on.
- [B] `TransitionMotion` got an all-around clearer API. See the [upgrade guide](https://github.com/chenglou/react-motion/wiki) and [README section](https://github.com/chenglou/react-motion/blob/9877c311cc4a22099eb56fe7c76bad9753519ddb/README.md#transitionmotion-) for more.
- [B] `Motion`'s' `defaultStyle`, informally accepted the format `{x: spring(0)}`. This is now officially unsupported. The correct format has always been `{x: 0}`. Setting a default style of `{x: spring(whatever)}` did not make sense; the configuration only applies for a `style`, aka destination value. Same modification applies to `StaggeredMotion` and `TransitionMotion`'s `defaultStyles` & `willEnter`.
- [B] `TransitionMotion`'s `willEnter`/`willLeave`'s signature has changed.
- [B] The `reorderKeys` helper is no longer needed thanks to the changes to `TransitionMotion`. It's now removed.
- [B] React-Native specific build gone. RN 0.18+ uses the vanilla Npm React package, so there's no more need for us to export a wrapper.
- [F] Bunch of bugs gone: #225, #212, #179, #157, #90, #88.
- [I] `spring` has acquired a new field as part of the new signature: [precision tuning](https://github.com/chenglou/react-motion/blob/9877c311cc4a22099eb56fe7c76bad9753519ddb/README.md#--spring-val-number-config-springhelperconfig--opaqueconfig)!
- [I] [Fully typed](https://github.com/chenglou/react-motion/blob/05d76f5ec7e9722dbca0237a97c41267e297eb2c/src/Types.js) via [Flow types](http://flowtype.org).
- [I] Performance improvements.

### 0.3.1 (October 14th 2015)
- [F] Handle `null` and `undefined` in `style`/`styles`. #181
- [I] Library's now partially annotated with [Flow](http://flowtype.org).
- [I] Related to above, the `src/` folder is now exposed on npm so that you can take advantage of Flow by using: `import {Motion} from 'react-motion/src/react-motion'` directly, instead of the old, prebuilt `import {Motion} from 'react-motion'`. **This is experimental** and intentionally undocumented. You'll have to adjust your webpack/browserify configurations to require these original source files correctly. No harm trying of course. It's just some type annotations =).

### 0.3.0 (September 30th 2015)
- [B] API revamp! See [https://github.com/chenglou/react-motion/wiki](https://github.com/chenglou/react-motion/wiki) for more details. Thanks!

### 0.2.7 (August 6th 2015)
- [F] Small bug where nested springs don't animate. #123
- [I] Support for all React 0.14.0 betas.

### 0.2.6 (July 31th 2015)
- [F] React-native warning's now gone, but also put into a separate file path. To require react-motion on react-native, do `require('react-motion/native')`.
- [I] Support for React 0.14.0-beta1.

### 0.2.4 (July 29th 2015)
- [I] React-native support!
- [I] Allow returning `null` from children function. #101
- [I] `defaultValue` for specifying a... default value, upon mounting.
- [I] `TransitionSpring`'s `willLeave` API got simplified and now asks for an object as a return value instead of `null`. `null` is still supported, but is deprecated and will be removed in the next version. See the new docs on it [here](https://github.com/chenglou/react-motion/blob/24d6a7284ef61268c0ead67fe43d7e40bf45d381/README.md#transitionspring-).
- [I] Exposed a few tasteful default spring configurations under the new exported `presets`.

### 0.2.2 (July 24th 2015)
- [F] Import some internal modules correctly for Ubuntu/Linux node (case-sensitive for them).
- [F] Nested springs work again.

### 0.2.0 (July 22th 2015)
- [B] `willLeave` returning `false` will now keep the key. Only `null` and `undefined` will serve as a signal to kill the disappeared key.
- [B] `willLeave` previously failed to expose the second argument `correspondingValueOfKeyThatJustLeft`. It's now exposed correctly.
- [F] Definitively fix the previous problem of mis-detecting React Element as object.
- [F] `willLeave` is now called only once per disappearing key. It was called more than once previously as a implementation detail. Though you should never have put side-effects in `willLeave`. It's still discouraged now.
- [F] If you have some `this.props.handlerThatSetStateAndUnmountsSpringInOwnerRender()` in `Spring`'s `endValue`, Spring's already scheduled `requestAnimationFrame` will no longer cause an extra `setState` since it's unmounted. But in general, _please_ don't put side-effect in `endValue`.
- [I] Stabilize the spring algorithm. No more erratic behavior with a big amount of animated items or tab switching (which usually slows down `requestAnimationFrame`). #57
- [I] Partial (total?) support for IE9 by using a `requestAnimationFrame` polyfill.

### 0.1.0 (July 14th 2015)
- [B] Breaking API: `TransitionSpring`'s `willEnter`'s callback signature is now `(keyThatEnters, correspondingValue, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)` (added `correspondingValue` as the second argument). Same for `willLeave`.
- [B] `Spring` is now no longer exposed as a default, but simply as "Spring": `require('react-motion').Spring`. Or `import {Spring} from 'react-motion'`.
- [B] `Spring` and `TransitionSpring`'s `children` function now expect a ReactElement. The components will no longer wrap the return value in a `div` for you. #44 #20
- [I] Move React to from dependencies to peerDependencies. #35
- [I] Internal cleanups + tests, for happier contributors.
- [F] Mis-detecting React Element as object.
- [F] Accidentally updating values at the first level of `endValue` without `{val: ...}` wrapper.

### 0.0.3 (July 9th 2015)
- [I] Initial release.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 React Motion authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
# React-Motion

[![Build Status](https://travis-ci.org/chenglou/react-motion.svg?branch=master)](https://travis-ci.org/chenglou/react-motion)
[![npm version](https://badge.fury.io/js/react-motion.svg)](https://www.npmjs.com/package/react-motion)
[![Bower version](https://badge.fury.io/bo/react-motion.svg)](http://badge.fury.io/bo/react-motion)
[![react-motion channel on discord](https://img.shields.io/badge/discord-react--motion%40reactiflux-738bd7.svg?style=flat)](https://discordapp.com/invite/0ZcbPKXt5bYzmcI0)

```js
import {Motion, spring} from 'react-motion';
// In your render...
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
  {value => <div>{value.x}</div>}
</Motion>
```

Animate a counter from `0` to `10`. For more advanced usage, see below.

### Install

- Npm: `npm install --save react-motion`

- Bower: **do not install with `bower install react-motion`, it won't work**. Use `bower install --save https://unpkg.com/react-motion/bower.zip`. Or in `bower.json`:
```json
{
  "dependencies": {
    "react-motion": "https://unpkg.com/react-motion/bower.zip"
  }
}
```
then include as
```html
<script src="bower_components/react-motion/build/react-motion.js"></script>
```

- 1998 Script Tag:
```html
<script src="https://unpkg.com/react-motion/build/react-motion.js"></script>
(Module exposed as `ReactMotion`)
```

**Works with React-Native v0.18+**.

### Demos
- [Simple Transition](http://chenglou.github.io/react-motion/demos/demo0-simple-transition)
- [Chat Heads](http://chenglou.github.io/react-motion/demos/demo1-chat-heads)
- [Draggable Balls](http://chenglou.github.io/react-motion/demos/demo2-draggable-balls)
- [TodoMVC List Transition](http://chenglou.github.io/react-motion/demos/demo3-todomvc-list-transition)
- [Photo Gallery](http://chenglou.github.io/react-motion/demos/demo4-photo-gallery)
- [Spring Parameters Chooser](http://chenglou.github.io/react-motion/demos/demo5-spring-parameters-chooser)
- [Water Ripples](http://chenglou.github.io/react-motion/demos/demo7-water-ripples)
- [Draggable List](http://chenglou.github.io/react-motion/demos/demo8-draggable-list)

[Check the wiki for more!](https://github.com/chenglou/react-motion/wiki/Gallery-of-third-party-React-Motion-demos)

### Try the Demos Locally
```sh
git clone https://github.com/chenglou/react-motion.git
cd react-motion
npm install
```

- With hot reloading (**slow, development version**): run `npm start`.
- Without hot reloading (**faster, production version**): run `npm run build-demos` and open the static `demos/demo_name/index.html` file directly. **Don't forget to use production mode when testing your animation's performance**!

To build the repo yourself: `npm run prepublish`.

## What does this library try to solve?

[My React-Europe talk](https://www.youtube.com/watch?v=1tavDv5hXpo)

For 95% of use-cases of animating components, we don't have to resort to using hard-coded easing curves and duration. Set up a stiffness and damping for your UI element, and let the magic of physics take care of the rest. This way, you don't have to worry about petty situations such as interrupted animation behavior. It also greatly simplifies the API.

This library also provides an alternative, more powerful API for React's `TransitionGroup`.

## API

Exports:
- `spring`
- `Motion`
- `StaggeredMotion`
- `TransitionMotion`
- `presets`

[Here](https://github.com/chenglou/react-motion/blob/9cb90eca20ecf56e77feb816d101a4a9110c7d70/src/Types.js)'s the well-annotated public [Flow type](http://flowtype.org) definition file (you don't have to use Flow with React-motion, but the types help document the API below).

P.S. using TypeScript? [Here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-motion/index.d.ts) are the React-motion TypeScript definitions!

---

### Helpers

##### - spring: (val: number, config?: SpringHelperConfig) => OpaqueConfig
Used in conjunction with the components below. Specifies the how to animate to the destination value, e.g. `spring(10, {stiffness: 120, damping: 17})` means "animate to value 10, with a spring of stiffness 120 and damping 17".

- `val`: the value.
- `config`: optional, for further adjustments. Possible fields:
  - `stiffness`: optional, defaults to `170`.
  - `damping`: optional, defaults to `26`.
  - `precision`: optional, defaults to `0.01`. Specifies both the rounding of the interpolated value and the speed (internal).

  It's normal not to feel how stiffness and damping affect your spring; use [Spring Parameters Chooser](http://chenglou.github.io/react-motion/demos/demo5-spring-parameters-chooser) to get a feeling. **Usually**, you'd just use the list of tasteful stiffness/damping presets below.

##### - Presets for `{stiffness, damping}`
Commonly used spring configurations used like so: `spring(10, presets.wobbly)` or `spring(20, {...presets.gentle, precision: 0.1})`. [See here](https://github.com/chenglou/react-motion/blob/9cb90eca20ecf56e77feb816d101a4a9110c7d70/src/presets.js).

---

### &lt;Motion />
#### Usage
```jsx
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
  {interpolatingStyle => <div style={interpolatingStyle} />}
</Motion>
```

#### Props

##### - style: Style

Required. The `Style` type is an object that maps to either a `number` or an `OpaqueConfig` returned by `spring()` above. Must keep the same keys throughout component's existence. The meaning of the values:

- an `OpaqueConfig` returned from `spring(x)`: interpolate to `x`.
- a `number` `x`: jump to `x`, do not interpolate.

##### - defaultStyle?: PlainStyle
Optional. The `PlainStyle` type maps to `number`s. Defaults to an object with the same keys as `style` above, whose values are the initial numbers you're interpolating on. **Note that during subsequent renders, this prop is ignored. The values will interpolate from the current ones to the destination ones (specified by `style`)**.

##### - children: (interpolatedStyle: PlainStyle) => ReactElement
Required **function**.

- `interpolatedStyle`: the interpolated style object passed back to you. E.g. if you gave `style={{x: spring(10), y: spring(20)}}`, you'll receive as `interpolatedStyle`, at a certain time, `{x: 5.2, y: 12.1}`, which you can then apply on your `div` or something else.

- Return: must return **one** React element to render.

##### - onRest?: () => void
Optional. The callback that fires when the animation comes to a rest.

---

### &lt;StaggeredMotion />
Animates a collection of (**fixed length**) items whose values depend on each other, creating a natural, springy, "staggering" effect [like so](http://chenglou.github.io/react-motion/demos/demo1-chat-heads). This is preferred over hard-coding a delay for an array of `Motions` to achieve a similar (but less natural-looking) effect.

#### Usage
```jsx
<StaggeredMotion
  defaultStyles={[{h: 0}, {h: 0}, {h: 0}]}
  styles={prevInterpolatedStyles => prevInterpolatedStyles.map((_, i) => {
    return i === 0
      ? {h: spring(100)}
      : {h: spring(prevInterpolatedStyles[i - 1].h)}
  })}>
  {interpolatingStyles =>
    <div>
      {interpolatingStyles.map((style, i) =>
        <div key={i} style={{border: '1px solid', height: style.h}} />)
      }
    </div>
  }
</StaggeredMotion>
```

Aka "the current spring's destination value is the interpolating value of the previous spring". Imagine a spring dragging another. Physics, it works!

#### Props

##### - styles: (previousInterpolatedStyles: ?Array&lt;PlainStyle>) => Array&lt;Style>
Required **function**. **Don't forget the "s"**!

- `previousInterpolatedStyles`: the previously interpolating (array of) styles (`undefined` at first render, unless `defaultStyles` is provided).

- Return: must return an array of `Style`s containing the destination values, e.g. `[{x: spring(10)}, {x: spring(20)}]`.

##### - defaultStyles?: Array&lt;PlainStyle>
Optional. Similar to `Motion`'s `defaultStyle`, but an array of them.

##### - children: (interpolatedStyles: Array&lt;PlainStyle>) => ReactElement
Required **function**. Similar to `Motion`'s `children`, but accepts the array of interpolated styles instead, e.g. `[{x: 5}, {x: 6.4}, {x: 8.1}]`

(No `onRest` for StaggeredMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)

---

### &lt;TransitionMotion />
**Helps you to do mounting and unmounting animation**.

#### Usage

You have items `a`, `b`, `c`, with their respective style configuration, given to `TransitionMotion`'s `styles`. In its `children` function, you're passed the three interpolated styles as params; you map over them and produce three components. All is good.

During next render, you give only `a` and `b`, indicating that you want `c` gone, but that you'd like to animate it reaching value `0`, before killing it for good.

Fortunately, `TransitionMotion` has kept `c` around and still passes it into the `children` function param. So when you're mapping over these three interpolated styles, you're still producing three components. It'll keep interpolating, while checking `c`'s current value at every frame. Once `c` reaches the specified `0`, `TransitionMotion` will remove it for good (from the interpolated styles passed to your `children` function).

This time, when mapping through the two remaining interpolated styles, you'll produce only two components. `c` is gone for real.

```jsx
import createReactClass from 'create-react-class';

const Demo = createReactClass({
  getInitialState() {
    return {
      items: [{key: 'a', size: 10}, {key: 'b', size: 20}, {key: 'c', size: 30}],
    };
  },
  componentDidMount() {
    this.setState({
      items: [{key: 'a', size: 10}, {key: 'b', size: 20}], // remove c.
    });
  },
  willLeave() {
    // triggered when c's gone. Keeping c until its width/height reach 0.
    return {width: spring(0), height: spring(0)};
  },
  render() {
    return (
      <TransitionMotion
        willLeave={this.willLeave}
        styles={this.state.items.map(item => ({
          key: item.key,
          style: {width: item.size, height: item.size},
        }))}>
        {interpolatedStyles =>
          // first render: a, b, c. Second: still a, b, c! Only last one's a, b.
          <div>
            {interpolatedStyles.map(config => {
              return <div key={config.key} style={{...config.style, border: '1px solid'}} />
            })}
          </div>
        }
      </TransitionMotion>
    );
  },
});
```

#### Props

First, two type definitions to ease the comprehension.

- `TransitionStyle`: an object of the format `{key: string, data?: any, style: Style}`.

  - `key`: required. The ID that `TransitionMotion` uses to track which configuration is which across renders, even when things are reordered. Typically reused as the component `key` when you map over the interpolated styles.

  - `data`: optional. Anything you'd like to carry along. This is so that when the previous section example's `c` disappears, you still get to access `c`'s related data, such as the text to display along with it.

  - `style`: required. The actual starting style configuration, similar to what you provide for `Motion`'s `style`. Maps keys to either a number or an `OpaqueConfig` returned by `spring()`.

- `TransitionPlainStyle`: similar to above, except the `style` field's value is of type `PlainStyle`, aka an object that maps to numbers.

##### - styles: Array&lt;TransitionStyle> | (previousInterpolatedStyles: ?Array&lt;TransitionPlainStyle>) => Array&lt;TransitionStyle>
Required. Accepts either:

  - an array of `TransitionStyle` configs, e.g. `[{key: 'a', style: {x: spring(0)}}, {key: 'b', style: {x: spring(10)}}]`.

  - a function similar to `StaggeredMotion`, taking the previously interpolating styles (`undefined` at first call, unless `defaultStyles` is provided), and returning the previously mentioned array of configs. __You can do staggered mounting animation with this__.

##### - defaultStyles?: Array&lt;TransitionPlainStyle>
Optional. Similar to the other components' `defaultStyle`/`defaultStyles`.

##### - children: (interpolatedStyles: Array&lt;TransitionPlainStyle>) => ReactElement
Required **function**. Similar to other two components' `children`. Receive back an array similar to what you provided for `defaultStyles`, only that each `style` object's number value represent the currently interpolating value.

##### - willLeave?: (styleThatLeft: TransitionStyle) => ?Style
Optional. Defaults to `() => null`. **The magic sauce property**.

- `styleThatLeft`: the e.g. `{key: ..., data: ..., style: ...}` object from the `styles` array, identified by `key`, that was present during a previous render, and that is now absent, thus triggering the call to `willLeave`. Note that the style property is exactly what you passed in `styles`, and is not interpolated. For example, if you passed a spring for `x` you will receive an object like `{x: {stiffness, damping, val, precision}}`.

- Return: `null` to indicate you want the `TransitionStyle` gone immediately. A `Style` object to indicate you want to reach transition to the specified value(s) before killing the `TransitionStyle`.

##### - didLeave?: (styleThatLeft: `{key: string, data?: any}`) => void
Optional. Defaults to `() => {}`.

- `styleThatLeft`: the `{key:..., data:...}` that was removed after the finished transition.

##### - willEnter?: (styleThatEntered: TransitionStyle) => PlainStyle
Optional. Defaults to `styleThatEntered => stripStyle(styleThatEntered.style)`. Where `stripStyle` turns `{x: spring(10), y: spring(20)}` into `{x: 10, y: 20}`.

- `styleThatEntered`: similar to `willLeave`'s, except the `TransitionStyle` represents the object whose `key` value was absent during the last `render`, and that is now present.

- Return: a `defaultStyle`-like `PlainStyle` configuration, e.g. `{x: 0, y: 0}`, that serves as the starting values of the animation. Under this light, the default provided means "a style config that has the same starting values as the destination values".

**Note** that `willEnter` and `defaultStyles` serve different purposes. `willEnter` only triggers when a previously inexistent `TransitionStyle` inside `styles` comes into the new render.

(No `onRest` for TransitionMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)

---

## FAQ

- How do I set the duration of my animation?

[Hard-coded duration goes against fluid interfaces](https://twitter.com/andy_matuschak/status/566736015188963328). If your animation is interrupted mid-way, you'd get a weird completion animation if you hard-coded the time. That being said, in the demo section there's a great [Spring Parameters Chooser](http://chenglou.github.io/react-motion/demos/demo5-spring-parameters-chooser) for you to have a feel of what spring is appropriate, rather than guessing a duration in the dark.

- How do I unmount the `TransitionMotion` container itself?

You don't. Unless you put it in another `TransitionMotion`...

- How do I do staggering/chained animation where items animate in one after another?

See [`StaggeredMotion`](#staggeredmotion-)

- My `ref` doesn't work in the children function.

React string refs won't work:

```jsx
<Motion style={...}>{currentValue => <div ref="stuff" />}</Motion>
```

This is how React works. Here's the [callback ref solution](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs).


================================================
FILE: bower.json
================================================
{
  "name": "react-motion",
  "version": "0.5.1",
  "homepage": "https://github.com/chenglou/react-motion",
  "authors": [
    "chenglou"
  ],
  "description": "A spring that solves your animation problems.",
  "main": [
    "build/react-motion.js",
    "build/react-motion.map"
  ],
  "dependencies": {
    "react": "^0.14.9 || ^15.3.0"
  },
  "keywords": [
    "react",
    "component",
    "react-component",
    "transitiongroup",
    "spring",
    "tween",
    "motion",
    "animation",
    "transition",
    "ui"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "test",
    "demo*",
    "server.js",
    "src",
    "webpack.config.js",
    "webpack.prod.config.js",
    "karma.conf.js",
    "package.json"
  ]
}


================================================
FILE: demos/README.md
================================================
## Demos folder

**Note**: since this is the master branch, the demos might be a bit ahead of the current stable API. [This commit](https://github.com/chenglou/react-motion/tree/0627243316c564f6c2f480bf615b82135f649a0a/demos) contains the stable demos.


================================================
FILE: demos/demo0-simple-transition/Demo.jsx
================================================
import React from 'react';
import {Motion, spring} from '../../src/react-motion';

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {open: false};
  };

  handleMouseDown = () => {
    this.setState({open: !this.state.open});
  };

  handleTouchStart = (e) => {
    e.preventDefault();
    this.handleMouseDown();
  };

  render() {
    return (
      <div>
        <button
          onMouseDown={this.handleMouseDown}
          onTouchStart={this.handleTouchStart}>
          Toggle
        </button>

        <Motion style={{x: spring(this.state.open ? 400 : 0)}}>
          {({x}) =>
            // children is a callback which should accept the current value of
            // `style`
            <div className="demo0">
              <div className="demo0-block" style={{
                WebkitTransform: `translate3d(${x}px, 0, 0)`,
                transform: `translate3d(${x}px, 0, 0)`,
              }} />
            </div>
          }
        </Motion>
      </div>
    );
  };
}


================================================
FILE: demos/demo0-simple-transition/index.html
================================================
<!doctype html>
<html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<head>
  <meta charset="UTF-8">
  <title>Toggle</title>
  <style>
  .demo0 {
    border-radius: 4px;
    background-color: rgb(240, 240, 232);
    position: relative;
    margin: 5px 3px 10px;
    width: 450px;
    height: 50px;
  }
  .demo0-block {
    position: absolute;
    width: 50px;
    height: 50px;
    border-radius: 4px;
    background-color: rgb(130, 181, 198);
  }
  </style>
</head>
<body>

<div id="content"></div>

<script src="./all.js"></script>

</body>
</html>


================================================
FILE: demos/demo0-simple-transition/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo1-chat-heads/Demo.jsx
================================================
import React from 'react';
import {StaggeredMotion, spring, presets} from '../../src/react-motion';
import range from 'lodash.range';

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {x: 250, y: 300};
  };

  componentDidMount() {
    window.addEventListener('mousemove', this.handleMouseMove);
    window.addEventListener('touchmove', this.handleTouchMove);
  };

  handleMouseMove = ({pageX: x, pageY: y}) => {
    this.setState({x, y});
  };

  handleTouchMove = ({touches}) => {
    this.handleMouseMove(touches[0]);
  };

  getStyles = (prevStyles) => {
    // `prevStyles` is the interpolated value of the last tick
    const endValue = prevStyles.map((_, i) => {
      return i === 0
        ? this.state
        : {
          x: spring(prevStyles[i - 1].x, presets.gentle),
          y: spring(prevStyles[i - 1].y, presets.gentle),
        };
    });
    return endValue;
  };

  render() {
    return (
      <StaggeredMotion
        defaultStyles={range(6).map(() => ({x: 0, y: 0}))}
        styles={this.getStyles}>
        {balls =>
          <div className="demo1">
            {balls.map(({x, y}, i) =>
              <div
                key={i}
                className={`demo1-ball ball-${i}`}
                style={{
                  WebkitTransform: `translate3d(${x - 25}px, ${y - 25}px, 0)`,
                  transform: `translate3d(${x - 25}px, ${y - 25}px, 0)`,
                  zIndex: balls.length - i,
                }} />
            )}
          </div>
        }
      </StaggeredMotion>
    );
  };
}


================================================
FILE: demos/demo1-chat-heads/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Chat Heads</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <style>
  * {
    margin: 0;
  }

  .demo1 {
    width: 100%;
    height: 100%;
    position: absolute;
    background: #EEE;
  }

  .demo1-ball {
    border-radius: 99px;
    background-color: white;
    width: 50px;
    height: 50px;
    border: 3px solid white;
    position: absolute;
    background-size: 50px;
  }

  .ball-0 {
    background-image: url(0.jpg);
  }

  .ball-1 {
    background-image: url(1.jpg);
  }

  .ball-2 {
    background-image: url(2.jpg);
  }

  .ball-3 {
    background-image: url(3.jpg);
  }

  .ball-4 {
    background-image: url(4.jpg);
  }

  .ball-5 {
    background-image: url(5.jpg);
  }
  </style>
</head>

<body>
  <div id="content"></div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo1-chat-heads/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo2-draggable-balls/Demo.jsx
================================================
import React from 'react';
import {Motion, spring} from '../../src/react-motion';
import range from 'lodash.range';

const springSetting1 = {stiffness: 180, damping: 10};
const springSetting2 = {stiffness: 120, damping: 17};
function reinsert(arr, from, to) {
  const _arr = arr.slice(0);
  const val = _arr[from];
  _arr.splice(from, 1);
  _arr.splice(to, 0, val);
  return _arr;
}

function clamp(n, min, max) {
  return Math.max(Math.min(n, max), min);
}

const allColors = [
  '#EF767A', '#456990', '#49BEAA', '#49DCB1', '#EEB868', '#EF767A', '#456990',
  '#49BEAA', '#49DCB1', '#EEB868', '#EF767A',
];
const [count, width, height] = [11, 70, 90];
// indexed by visual position
const layout = range(count).map(n => {
  const row = Math.floor(n / 3);
  const col = n % 3;
  return [width * col, height * row];
});

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      mouseXY: [0, 0],
      mouseCircleDelta: [0, 0], // difference between mouse and circle pos for x + y coords, for dragging
      lastPress: null, // key of the last pressed component
      isPressed: false,
      order: range(count), // index: visual position. value: component key/id
    };
  };

  componentDidMount() {
    window.addEventListener('touchmove', this.handleTouchMove);
    window.addEventListener('touchend', this.handleMouseUp);
    window.addEventListener('mousemove', this.handleMouseMove);
    window.addEventListener('mouseup', this.handleMouseUp);
  };

  handleTouchStart = (key, pressLocation, e) => {
    this.handleMouseDown(key, pressLocation, e.touches[0]);
  };

  handleTouchMove = (e) => {
    e.preventDefault();
    this.handleMouseMove(e.touches[0]);
  };

  handleMouseMove = ({pageX, pageY}) => {
    const {order, lastPress, isPressed, mouseCircleDelta: [dx, dy]} = this.state;
    if (isPressed) {
      const mouseXY = [pageX - dx, pageY - dy];
      const col = clamp(Math.floor(mouseXY[0] / width), 0, 2);
      const row = clamp(Math.floor(mouseXY[1] / height), 0, Math.floor(count / 3));
      const index = row * 3 + col;
      const newOrder = reinsert(order, order.indexOf(lastPress), index);
      this.setState({mouseXY, order: newOrder});
    }
  };

  handleMouseDown = (key, [pressX, pressY], {pageX, pageY}) => {
    this.setState({
      lastPress: key,
      isPressed: true,
      mouseCircleDelta: [pageX - pressX, pageY - pressY],
      mouseXY: [pressX, pressY],
    });
  };

  handleMouseUp = () => {
    this.setState({isPressed: false, mouseCircleDelta: [0, 0]});
  };

  render() {
    const {order, lastPress, isPressed, mouseXY} = this.state;
    return (
      <div className="demo2">
        {order.map((_, key) => {
          let style;
          let x;
          let y;
          const visualPosition = order.indexOf(key);
          if (key === lastPress && isPressed) {
            [x, y] = mouseXY;
            style = {
              translateX: x,
              translateY: y,
              scale: spring(1.2, springSetting1),
              boxShadow: spring((x - (3 * width - 50) / 2) / 15, springSetting1),
            };
          } else {
            [x, y] = layout[visualPosition];
            style = {
              translateX: spring(x, springSetting2),
              translateY: spring(y, springSetting2),
              scale: spring(1, springSetting1),
              boxShadow: spring((x - (3 * width - 50) / 2) / 15, springSetting1),
            };
          }
          return (
            <Motion key={key} style={style}>
              {({translateX, translateY, scale, boxShadow}) =>
                <div
                  onMouseDown={this.handleMouseDown.bind(null, key, [x, y])}
                  onTouchStart={this.handleTouchStart.bind(null, key, [x, y])}
                  className="demo2-ball"
                  style={{
                    backgroundColor: allColors[key],
                    WebkitTransform: `translate3d(${translateX}px, ${translateY}px, 0) scale(${scale})`,
                    transform: `translate3d(${translateX}px, ${translateY}px, 0) scale(${scale})`,
                    zIndex: key === lastPress ? 99 : visualPosition,
                    boxShadow: `${boxShadow}px 5px 5px rgba(0,0,0,0.5)`,
                  }}
                />
              }
            </Motion>
          );
        })}
      </div>
    );
  };
}


================================================
FILE: demos/demo2-draggable-balls/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Grid of Balls</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
  * {
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }

  .demo2-outer {
    height: 100%;
    width: 100%;
    position: absolute;
    background-color: #EEE;
    display: flex;
    justify-content: center;
    align-items: center;
    display: -webkit-flex;
    -webkit-justify-content: center;
    -webkit-align-items: center;
  }

  .demo2 {
    width: 190px;
    height: 320px;
  }

  .demo2-ball {
    position: absolute;
    border: 1px solid black;
    border-radius: 99px;
    width: 50px;
    height: 50px;
  }
  </style>
</head>

<body>
  <div class="demo2-outer">
    <div id="content"></div>
  </div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo2-draggable-balls/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo3-todomvc-list-transition/Demo.jsx
================================================
import React from 'react';
import {TransitionMotion, spring, presets} from '../../src/react-motion';

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: [
        // key is creation date
        {key: 't1', data: {text: 'Board the plane', isDone: false}},
        {key: 't2', data: {text: 'Sleep', isDone: false}},
        {key: 't3', data: {text: 'Try to finish conference slides', isDone: false}},
        {key: 't4', data: {text: 'Eat cheese and drink wine', isDone: false}},
        {key: 't5', data: {text: 'Go around in Uber', isDone: false}},
        {key: 't6', data: {text: 'Talk with conf attendees', isDone: false}},
        {key: 't7', data: {text: 'Show Demo 1', isDone: false}},
        {key: 't8', data: {text: 'Show Demo 2', isDone: false}},
        {key: 't9', data: {text: 'Lament about the state of animation', isDone: false}},
        {key: 't10', data: {text: 'Show Secret Demo', isDone: false}},
        {key: 't11', data: {text: 'Go home', isDone: false}},
      ],
      value: '',
      selected: 'all',
    };
  };

  // logic from todo, unrelated to animation
  handleChange = ({target: {value}}) => {
    this.setState({value});
  };

  handleSubmit = (e) => {
    e.preventDefault();
    const newItem = {
      key: 't' + Date.now(),
      data: {text: this.state.value, isDone: false},
    };
    // append at head
    this.setState({todos: [newItem].concat(this.state.todos)});
  };

  handleDone = (doneKey) => {
    this.setState({
      todos: this.state.todos.map(todo => {
        const {key, data: {text, isDone}} = todo;
        return key === doneKey
          ? {key: key, data: {text: text, isDone: !isDone}}
          : todo;
      }),
    });
  };

  handleToggleAll = () => {
    const allNotDone = this.state.todos.every(({data}) => data.isDone);
    this.setState({
      todos: this.state.todos.map(({key, data: {text, isDone}}) => (
        {key: key, data: {text: text, isDone: !allNotDone}}
      )),
    });
  };

  handleSelect = (selected) => {
    this.setState({selected});
  };

  handleClearCompleted = () => {
    this.setState({todos: this.state.todos.filter(({data}) => !data.isDone)});
  };

  handleDestroy = (date) => {
    this.setState({todos: this.state.todos.filter(({key}) => key !== date)});
  };

  // actual animation-related logic
  getDefaultStyles = () => {
    return this.state.todos.map(todo => ({...todo, style: {height: 0, opacity: 1}}));
  };

  getStyles = () => {
    const {todos, value, selected} = this.state;
    return todos.filter(({data: {isDone, text}}) => {
      return text.toUpperCase().indexOf(value.toUpperCase()) >= 0 &&
        (selected === 'completed' && isDone ||
        selected === 'active' && !isDone ||
        selected === 'all');
    })
    .map((todo, i) => {
      return {
        ...todo,
        style: {
          height: spring(60, presets.gentle),
          opacity: spring(1, presets.gentle),
        }
      };
    });
  };

  willEnter() {
    return {
      height: 0,
      opacity: 1,
    };
  };

  willLeave() {
    return {
      height: spring(0),
      opacity: spring(0),
    };
  };

  render() {
    const {todos, value, selected} = this.state;
    const itemsLeft = todos.filter(({data: {isDone}}) => !isDone).length;
    return (
      <section className="todoapp">
        <header className="header">
          <h1>todos</h1>
          <form onSubmit={this.handleSubmit}>
            <input
              autoFocus={true}
              className="new-todo"
              placeholder="What needs to be done?"
              value={value}
              onChange={this.handleChange}
            />
          </form>
        </header>
        <section className="main">
          <input
            className="toggle-all"
            type="checkbox"
            checked={itemsLeft === 0} style={{display: todos.length === 0 ? 'none' : 'inline'}}
            onChange={this.handleToggleAll} />
          <TransitionMotion
            defaultStyles={this.getDefaultStyles()}
            styles={this.getStyles()}
            willLeave={this.willLeave}
            willEnter={this.willEnter}>
            {styles =>
              <ul className="todo-list">
                {styles.map(({key, style, data: {isDone, text}}) =>
                  <li key={key} style={style} className={isDone ? 'completed' : ''}>
                    <div className="view">
                      <input
                        className="toggle"
                        type="checkbox"
                        onChange={this.handleDone.bind(null, key)}
                        checked={isDone}
                      />
                      <label>{text}</label>
                      <button
                        className="destroy"
                        onClick={this.handleDestroy.bind(null, key)}
                      />
                    </div>
                  </li>
                )}
              </ul>
            }
          </TransitionMotion>
        </section>
        <footer className="footer">
          <span className="todo-count">
            <strong>
              {itemsLeft}
            </strong> {itemsLeft === 1 ? 'item' : 'items'} left
          </span>
          <ul className="filters">
            <li>
              <a
                className={selected === 'all' ? 'selected' : ''}
                onClick={this.handleSelect.bind(null, 'all')}>
                All
              </a>
            </li>
            <li>
              <a
                className={selected === 'active' ? 'selected' : ''}
                onClick={this.handleSelect.bind(null, 'active')}>
                Active
              </a>
            </li>
            <li>
              <a
                className={selected === 'completed' ? 'selected' : ''}
                onClick={this.handleSelect.bind(null, 'completed')}>
                Completed
              </a>
            </li>
          </ul>
          <button className="clear-completed" onClick={this.handleClearCompleted}>
            Clear completed
          </button>
        </footer>
      </section>
    );
  };
}


================================================
FILE: demos/demo3-todomvc-list-transition/index.css
================================================
hr {
  margin: 20px 0;
  border: 0;
  border-top: 1px dashed #c5c5c5;
  border-bottom: 1px dashed #f7f7f7;
}

.learn a {
  font-weight: normal;
  text-decoration: none;
  color: #b83f45;
}

.learn a:hover {
  text-decoration: underline;
  color: #787e7e;
}

.learn h3,
.learn h4,
.learn h5 {
  margin: 10px 0;
  font-weight: 500;
  line-height: 1.2;
  color: #000;
}

.learn h3 {
  font-size: 24px;
}

.learn h4 {
  font-size: 18px;
}

.learn h5 {
  margin-bottom: 0;
  font-size: 14px;
}

.learn ul {
  padding: 0;
  margin: 0 0 30px 25px;
}

.learn li {
  line-height: 20px;
}

.learn p {
  font-size: 15px;
  font-weight: 300;
  line-height: 1.3;
  margin-top: 0;
  margin-bottom: 0;
}

#issue-count {
  display: none;
}

.quote {
  border: none;
  margin: 20px 0 60px 0;
}

.quote p {
  font-style: italic;
}

.quote p:before {
  content: '“';
  font-size: 50px;
  opacity: .15;
  position: absolute;
  top: -20px;
  left: 3px;
}

.quote p:after {
  content: '”';
  font-size: 50px;
  opacity: .15;
  position: absolute;
  bottom: -42px;
  right: 3px;
}

.quote footer {
  position: absolute;
  bottom: -40px;
  right: 0;
}

.quote footer img {
  border-radius: 3px;
}

.quote footer a {
  margin-left: 5px;
  vertical-align: middle;
}

.speech-bubble {
  position: relative;
  padding: 10px;
  background: rgba(0, 0, 0, .04);
  border-radius: 5px;
}

.speech-bubble:after {
  content: '';
  position: absolute;
  top: 100%;
  right: 30px;
  border: 13px solid transparent;
  border-top-color: rgba(0, 0, 0, .04);
}

.learn-bar > .learn {
  position: absolute;
  width: 272px;
  top: 8px;
  left: -300px;
  padding: 10px;
  border-radius: 5px;
  background-color: rgba(255, 255, 255, .6);
  transition-property: left;
  transition-duration: 500ms;
}

@media (min-width: 899px) {
  .learn-bar {
    width: auto;
    padding-left: 300px;
  }

  .learn-bar > .learn {
    left: 8px;
  }
}

html,
body {
  margin: 0;
  padding: 0;
}

button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-size: 100%;
  vertical-align: baseline;
  font-family: inherit;
  font-weight: inherit;
  color: inherit;
  -webkit-appearance: none;
  appearance: none;
  -webkit-font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  font-smoothing: antialiased;
}

body {
  font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.4em;
  background: #f5f5f5;
  color: #4d4d4d;
  min-width: 230px;
  max-width: 550px;
  margin: 0 auto;
  -webkit-font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  font-smoothing: antialiased;
  font-weight: 300;
}

button,
input[type="checkbox"] {
  outline: none;
}

.hidden {
  display: none;
}

.todoapp {
  background: #fff;
  margin: 130px 0 40px 0;
  position: relative;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
              0 25px 50px 0 rgba(0, 0, 0, 0.1);
}

.todoapp input::-webkit-input-placeholder {
  font-style: italic;
  font-weight: 300;
  color: #e6e6e6;
}

.todoapp input::-moz-placeholder {
  font-style: italic;
  font-weight: 300;
  color: #e6e6e6;
}

.todoapp input::input-placeholder {
  font-style: italic;
  font-weight: 300;
  color: #e6e6e6;
}

.todoapp h1 {
  position: absolute;
  top: -155px;
  width: 100%;
  font-size: 100px;
  font-weight: 100;
  text-align: center;
  color: rgba(175, 47, 47, 0.15);
  -webkit-text-rendering: optimizeLegibility;
  -moz-text-rendering: optimizeLegibility;
  text-rendering: optimizeLegibility;
}

.new-todo,
.edit {
  position: relative;
  margin: 0;
  width: 100%;
  font-size: 24px;
  font-family: inherit;
  font-weight: inherit;
  line-height: 1.4em;
  border: 0;
  outline: none;
  color: inherit;
  padding: 6px;
  border: 1px solid #999;
  box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
  box-sizing: border-box;
  -webkit-font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  font-smoothing: antialiased;
}

.new-todo {
  padding: 16px 16px 16px 60px;
  border: none;
  background: rgba(0, 0, 0, 0.003);
  box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}

.main {
  position: relative;
  z-index: 2;
  border-top: 1px solid #e6e6e6;
}

label[for='toggle-all'] {
  display: none;
}

.toggle-all {
  position: absolute;
  top: -55px;
  left: -12px;
  width: 60px;
  height: 34px;
  text-align: center;
  border: none; /* Mobile Safari */
}

.toggle-all:before {
  content: '❯';
  font-size: 22px;
  color: #e6e6e6;
  padding: 10px 27px 10px 27px;
}

.toggle-all:checked:before {
  color: #737373;
}

.todo-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.todo-list li {
  position: relative;
  font-size: 24px;
  box-shadow: 0 -1px 0 #ededed;
  overflow: hidden;
}

.todo-list li:last-child {
  border-bottom: none;
}

.todo-list li.editing {
  border-bottom: none;
  padding: 0;
}

.todo-list li.editing .edit {
  display: block;
  width: 506px;
  padding: 13px 17px 12px 17px;
  margin: 0 0 0 43px;
}

.todo-list li.editing .view {
  display: none;
}

.todo-list li .toggle {
  text-align: center;
  width: 40px;
  /* auto, since non-WebKit browsers doesn't support input styling */
  height: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto 0;
  border: none; /* Mobile Safari */
  -webkit-appearance: none;
  appearance: none;
}

.todo-list li .toggle:after {
  content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}

.todo-list li .toggle:checked:after {
  content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}

.todo-list li label {
  white-space: pre;
  word-break: break-word;
  padding: 15px 60px 15px 15px;
  margin-left: 45px;
  display: block;
  line-height: 1.2;
  transition: color 0.4s;
}

.todo-list li.completed label {
  color: #d9d9d9;
  text-decoration: line-through;
}

.todo-list li .destroy {
  display: none;
  position: absolute;
  top: 0;
  right: 10px;
  bottom: 0;
  width: 40px;
  height: 40px;
  margin: auto 0;
  font-size: 30px;
  color: #cc9a9a;
  margin-bottom: 11px;
  transition: color 0.2s ease-out;
}

.todo-list li .destroy:hover {
  color: #af5b5e;
}

.todo-list li .destroy:after {
  content: '×';
}

.todo-list li:hover .destroy {
  display: block;
}

.todo-list li .edit {
  display: none;
}

.todo-list li.editing:last-child {
  margin-bottom: -1px;
}

.footer {
  color: #777;
  padding: 10px 15px;
  height: 20px;
  text-align: center;
  border-top: 1px solid #e6e6e6;
}

.footer:before {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 50px;
  overflow: hidden;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
              0 8px 0 -3px #f6f6f6,
              0 9px 1px -3px rgba(0, 0, 0, 0.2),
              0 16px 0 -6px #f6f6f6,
              0 17px 2px -6px rgba(0, 0, 0, 0.2);
}

.todo-count {
  float: left;
  text-align: left;
}

.todo-count strong {
  font-weight: 300;
}

.filters {
  margin: 0;
  padding: 0;
  list-style: none;
  position: absolute;
  right: 0;
  left: 0;
}

.filters li {
  display: inline;
}

.filters li a {
  color: inherit;
  margin: 3px;
  padding: 3px 7px;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 3px;
}

.filters li a.selected,
.filters li a:hover {
  border-color: rgba(175, 47, 47, 0.1);
}

.filters li a.selected {
  border-color: rgba(175, 47, 47, 0.2);
}

.clear-completed,
html .clear-completed:active {
  float: right;
  position: relative;
  line-height: 20px;
  text-decoration: none;
  cursor: pointer;
  position: relative;
}

.clear-completed:hover {
  text-decoration: underline;
}

.info {
  margin: 65px auto 0;
  color: #bfbfbf;
  font-size: 10px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
  text-align: center;
}

.info p {
  line-height: 1;
}

.info a {
  color: inherit;
  text-decoration: none;
  font-weight: 400;
}

.info a:hover {
  text-decoration: underline;
}

/*
  Hack to remove background from Mobile Safari.
  Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
  .toggle-all,
  .todo-list li .toggle {
    background: none;
  }

  .todo-list li .toggle {
    height: 40px;
  }

  .toggle-all {
    -webkit-transform: rotate(90deg);
    transform: rotate(90deg);
    -webkit-appearance: none;
    appearance: none;
  }
}

@media (max-width: 430px) {
  .footer {
    height: 50px;
  }

  .filters {
    bottom: 10px;
  }
}

================================================
FILE: demos/demo3-todomvc-list-transition/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>RedoMVC</title>
  <link rel="stylesheet" href="./index.css" />
</head>

<body>
  <div id="content"></div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo3-todomvc-list-transition/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo4-photo-gallery/Demo.jsx
================================================
import React from 'react';
import {Motion, spring} from '../../src/react-motion';

const springSettings = {stiffness: 170, damping: 26};
const NEXT = 'show-next';

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      photos: [[500, 350], [800, 600], [800, 400], [700, 500], [200, 650], [600, 600]],
      currPhoto: 0,
    };
  };

  handleChange = ({target: {value}}) => {
    this.setState({currPhoto: value});
  };

  clickHandler = (btn) => {
    let photoIndex = btn === NEXT ? this.state.currPhoto+1 : this.state.currPhoto-1;

    photoIndex = photoIndex >= 0 ? photoIndex : this.state.photos.length - 1;
    photoIndex = photoIndex >= this.state.photos.length ? 0 : photoIndex;

    this.setState({
      currPhoto: photoIndex
    })
  };

  render() {
    const {photos, currPhoto} = this.state;
    const [currWidth, currHeight] = photos[currPhoto];

    const widths = photos.map(([origW, origH]) => currHeight / origH * origW);

    const leftStartCoords = widths
      .slice(0, currPhoto)
      .reduce((sum, width) => sum - width, 0);

    let configs = [];
    photos.reduce((prevLeft, [origW, origH], i) => {
      configs.push({
        left: spring(prevLeft, springSettings),
        height: spring(currHeight, springSettings),
        width: spring(widths[i], springSettings),
      });
      return prevLeft + widths[i];
    }, leftStartCoords);

    return (
      <div>
        <div>Scroll Me</div>
        <button onClick={this.clickHandler.bind(null, '')}>Previous</button>
        <input
          type="range"
          min={0}
          max={photos.length - 1}
          value={currPhoto}
          onChange={this.handleChange} />
        <button onClick={this.clickHandler.bind(null, NEXT)}>Next</button>
        <div className="demo4">
          <Motion style={{height: spring(currHeight), width: spring(currWidth)}}>
            {container =>
              <div className="demo4-inner" style={container}>
                {configs.map((style, i) =>
                  <Motion key={i} style={style}>
                    {style =>
                      <img className="demo4-photo" src={`./${i}.jpg`} style={style} />
                    }
                  </Motion>
                )}
              </div>
            }
          </Motion>
        </div>
      </div>
    );
  };
}


================================================
FILE: demos/demo4-photo-gallery/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>How Many Demos Do You Need</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
  .demo4 {
    display: flex;
    display: -webkit-flex;
    align-items: center;
    height: 700px;
    position: relative;
  }

  .demo4-inner {
    overflow: hidden;
    position: relative;
    margin: auto;
  }

  .demo4-photo {
    position: absolute;
    background-color: lightgray;
  }
  </style>
</head>

<body>
  <div id="content"></div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo4-photo-gallery/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo5-spring-parameters-chooser/Demo.jsx
================================================
import React from 'react';
import {Motion, spring} from '../../src/react-motion';
import range from 'lodash.range';

const gridWidth = 150;
const gridHeight = 150;
const grid = range(4).map(() => range(6));

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      delta: [0, 0],
      mouse: [0, 0],
      isPressed: false,
      firstConfig: [60, 5],
      slider: {dragged: null, num: 0},
      lastPressed: [0, 0],
    };
  };

  componentDidMount() {
    window.addEventListener('mousemove', this.handleMouseMove);
    window.addEventListener('touchmove', this.handleTouchMove);
    window.addEventListener('mouseup', this.handleMouseUp);
    window.addEventListener('touchend', this.handleMouseUp);
  };

  handleTouchStart = (pos, press, e) => {
    this.handleMouseDown(pos, press, e.touches[0]);
  };

  handleMouseDown = (pos, [pressX, pressY], {pageX, pageY}) => {
    this.setState({
      delta: [pageX - pressX, pageY - pressY],
      mouse: [pressX, pressY],
      isPressed: true,
      lastPressed: pos,
    });
  };

  handleTouchMove = (e) => {
    if (this.state.isPressed) {
      e.preventDefault();
    }
    this.handleMouseMove(e.touches[0]);
  };

  handleMouseMove = ({pageX, pageY}) => {
    const {isPressed, delta: [dx, dy]} = this.state;
    if (isPressed) {
      this.setState({mouse: [pageX - dx, pageY - dy]});
    }
  };

  handleMouseUp = () => {
    this.setState({
      isPressed: false,
      delta: [0, 0],
      slider: {dragged: null, num: 0},
    });
  };

  handleChange = (constant, num, {target}) => {
    const {firstConfig: [s, d]} = this.state;
    if (constant === 'stiffness') {
      this.setState({
        firstConfig: [target.value - num * 30, d],
      });
    } else {
      this.setState({
        firstConfig: [s, target.value - num * 2],
      });
    }
  };

  handleMouseDownInput = (constant, num) => {
    this.setState({
      slider: {dragged: constant, num: num},
    });
  };

  render() {
    const {
      mouse, isPressed, lastPressed, firstConfig: [s0, d0], slider: {dragged, num},
    } = this.state;
    return (
      <div className="demo5">
        {grid.map((row, i) => {
          return row.map((cell, j) => {
            const cellStyle = {
              top: gridHeight * i,
              left: gridWidth * j,
              width: gridWidth,
              height: gridHeight,
            };
            const stiffness = s0 + i * 30;
            const damping = d0 + j * 2;
            const motionStyle = isPressed
              ? {x: mouse[0], y: mouse[1]}
              : {
                  x: spring(gridWidth / 2 - 25, {stiffness, damping}),
                  y: spring(gridHeight / 2 - 25, {stiffness, damping}),
                };

            return (
              <div style={cellStyle} className="demo5-cell">
                <input
                  type="range"
                  min={0}
                  max={300}
                  value={stiffness}
                  onMouseDown={this.handleMouseDownInput.bind(null, 'stiffness', i)}
                  onChange={this.handleChange.bind(null, 'stiffness', i)} />
                <input
                  type="range"
                  min={0}
                  max={40}
                  value={damping}
                  onMouseDown={this.handleMouseDownInput.bind(null, 'damping', j)}
                  onChange={this.handleChange.bind(null, 'damping', j)} />
                <Motion style={motionStyle}>
                  {({x, y}) => {
                    let thing;
                    if (dragged === 'stiffness') {
                      thing = i < num ? <div className="demo5-minus">-{(num - i) * 30}</div>
                        : i > num ? <div className="demo5-plus">+{(i - num) * 30}</div>
                        : <div className="demo5-plus">0</div>;
                    } else {
                      thing = j < num ? <div className="demo5-minus">-{(num - j) * 2}</div>
                        : j > num ? <div className="demo5-plus">+{(j - num) * 2}</div>
                        : <div className="demo5-plus">0</div>;
                    }
                    const active = lastPressed[0] === i && lastPressed[1] === j
                      ? 'demo5-ball-active'
                      : '';
                    return (
                      <div
                        style={{
                          transform: `translate3d(${x}px, ${y}px, 0)`,
                          WebkitTransform: `translate3d(${x}px, ${y}px, 0)`,
                        }}
                        className={'demo5-ball ' + active}
                        onMouseDown={this.handleMouseDown.bind(null, [i, j], [x, y])}
                        onTouchStart={this.handleTouchStart.bind(null, [i, j], [x, y])}>
                        <div className="demo5-preset">
                          {stiffness}{dragged === 'stiffness' && thing}
                        </div>
                        <div className="demo5-preset">
                          {damping}{dragged === 'damping' && thing}
                        </div>
                      </div>
                    );
                  }}
                </Motion>
              </div>
            );
          });
        })}
      </div>
    );
  };
}


================================================
FILE: demos/demo5-spring-parameters-chooser/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Choose your weapon</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
  * {
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }

  body {
    background-color: #FFFFFF;
    font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
    font-weight: 300;
  }

  h3 {
    margin: 5px 0 16px;
    font-size: 13px;
  }

  .demo5-outer {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    display: -webkit-flex;
    -webkit-flex-direction: column;
    -webkit-justify-content: center;
    -webkit-align-items: center;
  }

  .demo5 {
    width: 900px;
    height: 600px;
    position: relative;
  }

  .demo5-cell {
    position: absolute;
    border: 1px solid #E4E4E4;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    justify-content: center;
    display: -webkit-flex;
    -webkit-flex-wrap: wrap;
    -webkit-align-content: flex-start;
    -webkit-justify-content: center;
    padding: 6px;
    box-sizing: border-box;
  }

  .demo5-cell input {
    visibility: hidden;
    cursor: ew-resize;
  }

  .demo5-cell:hover input {
    visibility: visible;
  }

  .demo5-ball {
    width: 50px;
    height: 50px;
    border-radius: 99px;
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    display: -webkit-flex;
    -webkit-justify-content: center;
    -webkit-align-items: center;
    -webkit-flex-direction: column;
    top: 0;
    left: 0;
    cursor: pointer;
    font-size: 12px;
    background-color: #FDC3C3;
    z-index: 1;
  }

  .demo5-ball-active {
    background-color: #FF8585;
  }

  .demo5-minus {
    padding-left: 4px;
    color: #CC2E2E;
  }

  .demo5-plus {
    padding-left: 4px;
    color: #39A11E;
  }

  .demo5-preset {
    display: flex;
    justify-content: space-around;
    display: -webkit-flex;
    -webkit-justify-content: space-around;
    padding: 0 2px 0 2px;
  }
  </style>
</head>

<body>
  <div class="demo5-outer">
    <div>Default: {stiffness: 170, damping: 26}</div>
    <h3>Drag a circle to see the differences in animation behavior</h3>
    <div id="content"></div>
  </div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo5-spring-parameters-chooser/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo7-water-ripples/Demo.jsx
================================================
import React from 'react';
import {TransitionMotion, spring} from '../../src/react-motion';

const leavingSpringConfig = {stiffness: 60, damping: 15};

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {mouse: [], now: 't' + 0};
  };

  handleMouseMove = ({pageX, pageY}) => {
    // Make sure the state is queued and not batched.
    this.setState(() => {
      return {
        mouse: [pageX - 25, pageY - 25],
        now: 't' + Date.now(),
      };
    });
  };

  handleTouchMove = (e) => {
    e.preventDefault();
    this.handleMouseMove(e.touches[0]);
  };

  willLeave = (styleCell) => {
    return {
      ...styleCell.style,
      opacity: spring(0, leavingSpringConfig),
      scale: spring(2, leavingSpringConfig),
    };
  };

  render() {
    const {mouse: [mouseX, mouseY], now} = this.state;
    const styles = mouseX == null ? [] : [{
      key: now,
      style: {
        opacity: spring(1),
        scale: spring(0),
        x: spring(mouseX),
        y: spring(mouseY),
      }
    }];
    return (
      <TransitionMotion willLeave={this.willLeave} styles={styles}>
        {circles =>
          <div
            onMouseMove={this.handleMouseMove}
            onTouchMove={this.handleTouchMove}
            className="demo7">
            {circles.map(({key, style: {opacity, scale, x, y}}) =>
              <div
                key={key}
                className="demo7-ball"
                style={{
                  opacity: opacity,
                  scale: scale,
                  transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`,
                  WebkitTransform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`,
                }} />
            )}
          </div>
        }
      </TransitionMotion>
    );
  };
}


================================================
FILE: demos/demo7-water-ripples/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Ripples</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
  * {
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }

  .demo7 {
    background-color: #1B1B1B;
    position: absolute;
    width: 100%;
    height: 100%;
  }

  .demo7-ball {
    width: 50px;
    height: 50px;
    border-radius: 99px;
    position: absolute;
    border: 1px solid lightblue;
  }
  </style>
</head>

<body>
  <div id="content"></div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo7-water-ripples/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: demos/demo8-draggable-list/Demo.jsx
================================================
import React from 'react';
import {Motion, spring} from '../../src/react-motion';
import range from 'lodash.range';

function reinsert(arr, from, to) {
  const _arr = arr.slice(0);
  const val = _arr[from];
  _arr.splice(from, 1);
  _arr.splice(to, 0, val);
  return _arr;
}

function clamp(n, min, max) {
  return Math.max(Math.min(n, max), min);
}

const springConfig = {stiffness: 300, damping: 50};
const itemsCount = 4;

export default class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      topDeltaY: 0,
      mouseY: 0,
      isPressed: false,
      originalPosOfLastPressed: 0,
      order: range(itemsCount),
    };
  };

  componentDidMount() {
    window.addEventListener('touchmove', this.handleTouchMove);
    window.addEventListener('touchend', this.handleMouseUp);
    window.addEventListener('mousemove', this.handleMouseMove);
    window.addEventListener('mouseup', this.handleMouseUp);
  };

  handleTouchStart = (key, pressLocation, e) => {
    this.handleMouseDown(key, pressLocation, e.touches[0]);
  };

  handleTouchMove = (e) => {
    e.preventDefault();
    this.handleMouseMove(e.touches[0]);
  };

  handleMouseDown = (pos, pressY, {pageY}) => {
    this.setState({
      topDeltaY: pageY - pressY,
      mouseY: pressY,
      isPressed: true,
      originalPosOfLastPressed: pos,
    });
  };

  handleMouseMove = ({pageY}) => {
    const {isPressed, topDeltaY, order, originalPosOfLastPressed} = this.state;

    if (isPressed) {
      const mouseY = pageY - topDeltaY;
      const currentRow = clamp(Math.round(mouseY / 100), 0, itemsCount - 1);
      let newOrder = order;

      if (currentRow !== order.indexOf(originalPosOfLastPressed)){
        newOrder = reinsert(order, order.indexOf(originalPosOfLastPressed), currentRow);
      }

      this.setState({mouseY: mouseY, order: newOrder});
    }
  };

  handleMouseUp = () => {
    this.setState({isPressed: false, topDeltaY: 0});
  };

  render() {
    const {mouseY, isPressed, originalPosOfLastPressed, order} = this.state;

    return (
      <div className="demo8">
        {range(itemsCount).map(i => {
          const style = originalPosOfLastPressed === i && isPressed
            ? {
                scale: spring(1.1, springConfig),
                shadow: spring(16, springConfig),
                y: mouseY,
              }
            : {
                scale: spring(1, springConfig),
                shadow: spring(1, springConfig),
                y: spring(order.indexOf(i) * 100, springConfig),
              };
          return (
            <Motion style={style} key={i}>
              {({scale, shadow, y}) =>
                <div
                  onMouseDown={this.handleMouseDown.bind(null, i, y)}
                  onTouchStart={this.handleTouchStart.bind(null, i, y)}
                  className="demo8-item"
                  style={{
                    boxShadow: `rgba(0, 0, 0, 0.2) 0px ${shadow}px ${2 * shadow}px 0px`,
                    transform: `translate3d(0, ${y}px, 0) scale(${scale})`,
                    WebkitTransform: `translate3d(0, ${y}px, 0) scale(${scale})`,
                    zIndex: i === originalPosOfLastPressed ? 99 : i,
                  }}>
                  {order.indexOf(i) + 1}
                </div>
              }
            </Motion>
          );
        })}
      </div>
    );
  };
}


================================================
FILE: demos/demo8-draggable-list/index.html
================================================
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Framer cards</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
  * {
    padding: 0;
    margin: 0;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }

  body {
    cursor: url('cursor.png') 39 39, auto;
  }

  .demo8-outer {
    background-color: #EEE;
    color: #FFF;
    position: absolute;
    width: 100%;
    height: 100%;
    font: 28px/1em "Helvetica";
    display: flex;
    justify-content: center;
    align-items: center;
    display: -webkit-flex;
    -webkit-justify-content: center;
    -webkit-align-items: center;
  }

  .demo8 {
    width: 320px;
    height: 400px;
  }

  .demo8-item {
    position: absolute;
    width: 320px;
    height: 90px;
    overflow: visible;
    pointer-events: auto;
    transform-origin: 50% 50% 0px;
    border-radius: 4px;
    color: rgb(153, 153, 153);
    line-height: 96px;
    padding-left: 32px;
    font-size: 24px;
    font-weight: 400;
    background-color: rgb(255, 255, 255);
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
  }

  .link {
    position: absolute;
    color: rgb(76, 76, 76);
    text-decoration: none;
    font: 14px/1em "Helvetica";
    padding: 10px;
    top: 0;
    left: 0;
  }
  </style>
</head>

<body>
  <div class="demo8-outer">
    <div id="content"></div>
    <a class="link" href="http://framerjs.com/examples/preview/#list-sorting.framer">
      Original Framer.js Example
    </a>
  </div>
  <script src="./all.js"></script>
</body>

</html>


================================================
FILE: demos/demo8-draggable-list/index.jsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';

ReactDOM.render(<Demo />, document.querySelector('#content'));


================================================
FILE: karma.conf.js
================================================
'use strict';

var path = require('path');

var withCoverage = process.argv.indexOf('coverage') !== -1 || process.env.COVERAGE;

var webpackConfig = {
  mode: 'development',
  module: {
    rules: withCoverage ?
      [
        {
          test: /\.js$/,
          loader: 'babel-loader',
          include: [path.resolve('./test')]
        },
        {
          test: /\.js$/,
          loader: 'isparta-loader',
          include: [path.resolve('./src')]
        },
      ] :
      [
        {
          test: /\.js$/,
          loader: 'babel-loader',
          include: [path.resolve('./src'), path.resolve('./test')],
        },
      ],
  },
  stats: {
    colors: true,
  }
};

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      './node_modules/@babel/polyfill/browser.js',
      'test/index.js',
    ],
    webpack: webpackConfig,
    webpackMiddleware: {
      stats: {
        chunkModules: false,
        colors: true,
      },
    },
    exclude: [],
    preprocessors: {
      'test/index.js': ['webpack'],
    },
    reporters: ['jasmine-diff', 'progress'],
    jasmineDiffReporter: {
      pretty: true,
      color: {
        expectedBg: '',
        expectedFg: 'red',
        actualBg: '',
        actualFg: 'green',
        defaultBg: '',
        defaultFg: 'grey'
      }
    },
    coverageReporter: {
      dir: './coverage/',
      subdir: '.',
      reporters: [
        {type: 'html'},
        {type: 'lcovonly'},
        {type: 'text', file: 'text.txt'},
        {type: 'text-summary', file: 'text-summary.txt'},
      ],
    },
    captureTimeout: 90000,
    browserNoActivityTimeout: 60000,
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['ChromeHeadless'],
    singleRun: true,
  });
};


================================================
FILE: package.json
================================================
{
  "name": "react-motion",
  "version": "0.5.2",
  "description": "A spring that solves your animation problems.",
  "main": "lib/react-motion.js",
  "module": "lib/react-motion.esm.js",
  "peerDependencies": {
    "react": "^0.14.9 || ^15.3.0 || ^16.0.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.0.0-rc.1",
    "@babel/core": "^7.7.2",
    "@babel/plugin-proposal-class-properties": "^7.7.0",
    "@babel/plugin-transform-modules-commonjs": "^7.7.0",
    "@babel/plugin-transform-runtime": "^7.6.2",
    "@babel/polyfill": "^7.7.0",
    "@babel/preset-env": "^7.7.1",
    "@babel/preset-flow": "^7.0.0",
    "@babel/preset-react": "^7.7.0",
    "babel-eslint": "^10.0.3",
    "babel-loader": "^8.0.6",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "codemirror": "^5.5.0",
    "cross-env": "^5.2.0",
    "css-loader": "^0.28.11",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.0.0",
    "eslint-config-prettier": "^2.9.0",
    "eslint-loader": "^2.0.0",
    "eslint-plugin-flowtype": "^2.49.3",
    "eslint-plugin-import": "^2.13.0",
    "eslint-plugin-jsx-a11y": "^6.1.0",
    "eslint-plugin-react": "^7.10.0",
    "flow-bin": "^0.53.1",
    "flow-copy-source": "^1.1.0",
    "husky": "^0.14.3",
    "inject-loader": "^4.0.1",
    "isparta-loader": "^2.0.0",
    "jasmine-core": "^3.1.0",
    "karma": "^2.0.4",
    "karma-chrome-launcher": "^2.2.0",
    "karma-coverage": "^1.1.2",
    "karma-jasmine": "^1.1.2",
    "karma-jasmine-diff-reporter": "^1.2.0",
    "karma-webpack": "^3.0.0",
    "lint-staged": "^7.2.0",
    "lodash.range": "^3.0.1",
    "prettier": "^1.14.2",
    "react": ">=15.5.0",
    "react-codemirror": ">=0.1.2",
    "react-dom": ">=15.5.0",
    "rollup": "^0.62.0",
    "rollup-plugin-babel": "^4.3.3",
    "rollup-plugin-commonjs": "^9.1.4",
    "rollup-plugin-node-resolve": "^3.3.0",
    "rollup-plugin-replace": "^2.0.0",
    "rollup-plugin-size-snapshot": "^0.6.0",
    "rollup-plugin-uglify": "^4.0.0",
    "style-loader": "^0.21.0",
    "webpack": "^4.14.0",
    "webpack-command": "^0.4.0",
    "webpack-dev-server": "^3.1.4"
  },
  "scripts": {
    "start": "node server.js",
    "prebuild:dist": "rm -rf build",
    "build:dist": "rollup -c",
    "prebuild:lib": "rm -rf lib",
    "build:lib": "babel src --out-dir lib",
    "build:flow": "flow-copy-source -v src lib",
    "build": "npm run build:dist && npm run build:lib && npm run build:flow",
    "build-demos": "webpack",
    "lint": "eslint --ext .js,.jsx .",
    "flow_check": "flow check",
    "prepublishOnly": "npm run build",
    "test": "cross-env NODE_ENV=test karma start ./karma.conf.js --single-run",
    "test:travis": "cross-env NODE_ENV=test karma start ./karma.conf.js --single-run",
    "test:dev": "cross-env NODE_ENV=test karma start ./karma.conf.js --no-single-run --auto-watch",
    "test:cov": "cross-env NODE_ENV=test karma start ./karma.conf.js --single-run --reporters coverage",
    "gh-pages": "git fetch origin && git checkout gh-pages && git reset --hard origin/gh-pages && git rebase origin/master --force-rebase && npm run build-demos && git add . && git commit --amend --no-edit && git push origin gh-pages --force && git checkout master",
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "*.js": [
      "prettier --write",
      "git add"
    ]
  },
  "prettier": {
    "singleQuote": true,
    "trailingComma": "all"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/chenglou/react-motion.git"
  },
  "keywords": [
    "react",
    "component",
    "react-component",
    "transitiongroup",
    "spring",
    "tween",
    "motion",
    "animation",
    "transition",
    "ui"
  ],
  "author": [
    "nkbt",
    "chenglou"
  ],
  "license": "MIT",
  "dependencies": {
    "@babel/runtime": "7.7.2",
    "performance-now": "^2.1.0",
    "prop-types": "^15.5.8",
    "raf": "^3.1.0"
  }
}


================================================
FILE: rollup.config.js
================================================
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import replace from 'rollup-plugin-replace';
import { sizeSnapshot } from 'rollup-plugin-size-snapshot';
import { uglify } from 'rollup-plugin-uglify';
import pkg from './package.json';

const input = './src/react-motion.js';
const name = 'ReactMotion';
const globals = {
  react: 'React',
};

// treat as external "module/path" modules and reserved rollup paths
const external = id =>
  !id.startsWith('\0') && !id.startsWith('.') && !id.startsWith('/');

const getBabelOptions = () => ({
  babelrc: false,
  exclude: '**/node_modules/**',
  runtimeHelpers: true,
  plugins: [
    ['@babel/proposal-class-properties', { loose: true }],
    ['transform-react-remove-prop-types', { mode: 'unsafe-wrap' }],
    ['@babel/transform-runtime', { useESModules: true }],
  ],
  presets: [
    ['@babel/env', { modules: false, loose: true }],
    '@babel/flow',
    '@babel/react',
  ],
});

const commonjsOptions = {
  include: '**/node_modules/**',
};

export default [
  {
    input,
    output: { file: 'build/react-motion.js', format: 'umd', name, globals },
    external: Object.keys(globals),
    plugins: [
      nodeResolve(),
      babel(getBabelOptions()),
      commonjs(commonjsOptions),
      replace({ 'process.env.NODE_ENV': JSON.stringify('development') }),
      sizeSnapshot(),
    ],
  },

  {
    input,
    output: { file: 'build/react-motion.min.js', format: 'umd', name, globals },
    external: Object.keys(globals),
    plugins: [
      nodeResolve(),
      babel(getBabelOptions()),
      commonjs(commonjsOptions),
      replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
      sizeSnapshot(),
      uglify(),
    ],
  },

  {
    input,
    output: { file: pkg.module, format: 'esm' },
    external,
    plugins: [babel(getBabelOptions()), sizeSnapshot()],
  },
];


================================================
FILE: server.js
================================================
'use strict';

process.env.NODE_ENV = 'development';

var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
var port = process.env.PORT || 3000;

new WebpackDevServer(webpack(config), {
  publicPath: config.output.publicPath,
  hot: true,
  stats: {
    chunkModules: false,
    colors: true,
  }
}).listen(port, '0.0.0.0', function (err) {
  if (err) {
    console.log(err);
  }

  console.log('Listening at 0.0.0.0:' + port);
});


================================================
FILE: src/Motion.js
================================================
/* @flow */
import mapToZero from './mapToZero';
import stripStyle from './stripStyle';
import stepper from './stepper';
import defaultNow from 'performance-now';
import defaultRaf from 'raf';
import shouldStopAnimation from './shouldStopAnimation';
import React from 'react';
import PropTypes from 'prop-types';

import type {
  ReactElement,
  PlainStyle,
  Style,
  Velocity,
  MotionProps,
} from './Types';

const msPerFrame = 1000 / 60;

type MotionState = {
  currentStyle: PlainStyle,
  currentVelocity: Velocity,
  lastIdealStyle: PlainStyle,
  lastIdealVelocity: Velocity,
};

export default class Motion extends React.Component<MotionProps, MotionState> {
  static propTypes = {
    // TOOD: warn against putting a config in here
    defaultStyle: PropTypes.objectOf(PropTypes.number),
    style: PropTypes.objectOf(
      PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
    ).isRequired,
    children: PropTypes.func.isRequired,
    onRest: PropTypes.func,
  };

  constructor(props: MotionProps) {
    super(props);
    this.state = this.defaultState();
  }

  unmounting: boolean = false;
  wasAnimating: boolean = false;
  animationID: ?number = null;
  prevTime: number = 0;
  accumulatedTime: number = 0;

  defaultState(): MotionState {
    const { defaultStyle, style } = this.props;
    const currentStyle = defaultStyle || stripStyle(style);
    const currentVelocity = mapToZero(currentStyle);
    return {
      currentStyle,
      currentVelocity,
      lastIdealStyle: currentStyle,
      lastIdealVelocity: currentVelocity,
    };
  }

  // it's possible that currentStyle's value is stale: if props is immediately
  // changed from 0 to 400 to spring(0) again, the async currentStyle is still
  // at 0 (didn't have time to tick and interpolate even once). If we naively
  // compare currentStyle with destVal it'll be 0 === 0 (no animation, stop).
  // In reality currentStyle should be 400
  unreadPropStyle: ?Style = null;
  // after checking for unreadPropStyle != null, we manually go set the
  // non-interpolating values (those that are a number, without a spring
  // config)
  clearUnreadPropStyle = (destStyle: Style): void => {
    let dirty = false;
    let {
      currentStyle,
      currentVelocity,
      lastIdealStyle,
      lastIdealVelocity,
    } = this.state;

    for (let key in destStyle) {
      if (!Object.prototype.hasOwnProperty.call(destStyle, key)) {
        continue;
      }

      const styleValue = destStyle[key];
      if (typeof styleValue === 'number') {
        if (!dirty) {
          dirty = true;
          currentStyle = { ...currentStyle };
          currentVelocity = { ...currentVelocity };
          lastIdealStyle = { ...lastIdealStyle };
          lastIdealVelocity = { ...lastIdealVelocity };
        }

        currentStyle[key] = styleValue;
        currentVelocity[key] = 0;
        lastIdealStyle[key] = styleValue;
        lastIdealVelocity[key] = 0;
      }
    }

    if (dirty) {
      this.setState({
        currentStyle,
        currentVelocity,
        lastIdealStyle,
        lastIdealVelocity,
      });
    }
  };

  startAnimationIfNecessary = (): void => {
    if (this.unmounting || this.animationID != null) {
      return;
    }

    // TODO: when config is {a: 10} and dest is {a: 10} do we raf once and
    // call cb? No, otherwise accidental parent rerender causes cb trigger
    this.animationID = defaultRaf(timestamp => {
      // https://github.com/chenglou/react-motion/pull/420
      // > if execution passes the conditional if (this.unmounting), then
      // executes async defaultRaf and after that component unmounts and after
      // that the callback of defaultRaf is called, then setState will be called
      // on unmounted component.
      if (this.unmounting) {
        return;
      }

      // check if we need to animate in the first place
      const propsStyle: Style = this.props.style;
      if (
        shouldStopAnimation(
          this.state.currentStyle,
          propsStyle,
          this.state.currentVelocity,
        )
      ) {
        if (this.wasAnimating && this.props.onRest) {
          this.props.onRest();
        }

        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.wasAnimating = false;
        this.accumulatedTime = 0;
        return;
      }

      this.wasAnimating = true;

      const currentTime = timestamp || defaultNow();
      const timeDelta = currentTime - this.prevTime;
      this.prevTime = currentTime;
      this.accumulatedTime = this.accumulatedTime + timeDelta;
      // more than 10 frames? prolly switched browser tab. Restart
      if (this.accumulatedTime > msPerFrame * 10) {
        this.accumulatedTime = 0;
      }

      if (this.accumulatedTime === 0) {
        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.startAnimationIfNecessary();
        return;
      }

      let currentFrameCompletion =
        (this.accumulatedTime -
          Math.floor(this.accumulatedTime / msPerFrame) * msPerFrame) /
        msPerFrame;
      const framesToCatchUp = Math.floor(this.accumulatedTime / msPerFrame);

      let newLastIdealStyle: PlainStyle = {};
      let newLastIdealVelocity: Velocity = {};
      let newCurrentStyle: PlainStyle = {};
      let newCurrentVelocity: Velocity = {};

      for (let key in propsStyle) {
        if (!Object.prototype.hasOwnProperty.call(propsStyle, key)) {
          continue;
        }

        const styleValue = propsStyle[key];
        if (typeof styleValue === 'number') {
          newCurrentStyle[key] = styleValue;
          newCurrentVelocity[key] = 0;
          newLastIdealStyle[key] = styleValue;
          newLastIdealVelocity[key] = 0;
        } else {
          let newLastIdealStyleValue = this.state.lastIdealStyle[key];
          let newLastIdealVelocityValue = this.state.lastIdealVelocity[key];
          for (let i = 0; i < framesToCatchUp; i++) {
            [newLastIdealStyleValue, newLastIdealVelocityValue] = stepper(
              msPerFrame / 1000,
              newLastIdealStyleValue,
              newLastIdealVelocityValue,
              styleValue.val,
              styleValue.stiffness,
              styleValue.damping,
              styleValue.precision,
            );
          }
          const [nextIdealX, nextIdealV] = stepper(
            msPerFrame / 1000,
            newLastIdealStyleValue,
            newLastIdealVelocityValue,
            styleValue.val,
            styleValue.stiffness,
            styleValue.damping,
            styleValue.precision,
          );

          newCurrentStyle[key] =
            newLastIdealStyleValue +
            (nextIdealX - newLastIdealStyleValue) * currentFrameCompletion;
          newCurrentVelocity[key] =
            newLastIdealVelocityValue +
            (nextIdealV - newLastIdealVelocityValue) * currentFrameCompletion;
          newLastIdealStyle[key] = newLastIdealStyleValue;
          newLastIdealVelocity[key] = newLastIdealVelocityValue;
        }
      }

      this.animationID = null;
      // the amount we're looped over above
      this.accumulatedTime -= framesToCatchUp * msPerFrame;

      this.setState({
        currentStyle: newCurrentStyle,
        currentVelocity: newCurrentVelocity,
        lastIdealStyle: newLastIdealStyle,
        lastIdealVelocity: newLastIdealVelocity,
      });

      this.unreadPropStyle = null;

      this.startAnimationIfNecessary();
    });
  };

  componentDidMount() {
    this.prevTime = defaultNow();
    this.startAnimationIfNecessary();
  }

  UNSAFE_componentWillReceiveProps(props: MotionProps) {
    if (this.unreadPropStyle != null) {
      // previous props haven't had the chance to be set yet; set them here
      this.clearUnreadPropStyle(this.unreadPropStyle);
    }

    this.unreadPropStyle = props.style;
    if (this.animationID == null) {
      this.prevTime = defaultNow();
      this.startAnimationIfNecessary();
    }
  }

  componentWillUnmount() {
    this.unmounting = true;
    if (this.animationID != null) {
      defaultRaf.cancel(this.animationID);
      this.animationID = null;
    }
  }

  render(): ReactElement {
    const renderedChildren = this.props.children(this.state.currentStyle);
    return renderedChildren && React.Children.only(renderedChildren);
  }
}


================================================
FILE: src/StaggeredMotion.js
================================================
/* @flow */
import mapToZero from './mapToZero';
import stripStyle from './stripStyle';
import stepper from './stepper';
import defaultNow from 'performance-now';
import defaultRaf from 'raf';
import shouldStopAnimation from './shouldStopAnimation';
import React from 'react';
import PropTypes from 'prop-types';

import type {
  ReactElement,
  PlainStyle,
  Style,
  Velocity,
  StaggeredProps,
} from './Types';

const msPerFrame = 1000 / 60;

type StaggeredMotionState = {
  currentStyles: Array<PlainStyle>,
  currentVelocities: Array<Velocity>,
  lastIdealStyles: Array<PlainStyle>,
  lastIdealVelocities: Array<Velocity>,
};

function shouldStopAnimationAll(
  currentStyles: Array<PlainStyle>,
  styles: Array<Style>,
  currentVelocities: Array<Velocity>,
): boolean {
  for (let i = 0; i < currentStyles.length; i++) {
    if (
      !shouldStopAnimation(currentStyles[i], styles[i], currentVelocities[i])
    ) {
      return false;
    }
  }
  return true;
}

export default class StaggeredMotion extends React.Component<
  StaggeredProps,
  StaggeredMotionState,
> {
  static propTypes = {
    // TOOD: warn against putting a config in here
    defaultStyles: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.number)),
    styles: PropTypes.func.isRequired,
    children: PropTypes.func.isRequired,
  };

  constructor(props: StaggeredProps) {
    super(props);
    this.state = this.defaultState();
  }

  defaultState(): StaggeredMotionState {
    const { defaultStyles, styles } = this.props;
    const currentStyles: Array<PlainStyle> =
      defaultStyles || styles().map(stripStyle);
    const currentVelocities = currentStyles.map(currentStyle =>
      mapToZero(currentStyle),
    );
    return {
      currentStyles,
      currentVelocities,
      lastIdealStyles: currentStyles,
      lastIdealVelocities: currentVelocities,
    };
  }

  unmounting: boolean = false;
  animationID: ?number = null;
  prevTime = 0;
  accumulatedTime = 0;
  // it's possible that currentStyle's value is stale: if props is immediately
  // changed from 0 to 400 to spring(0) again, the async currentStyle is still
  // at 0 (didn't have time to tick and interpolate even once). If we naively
  // compare currentStyle with destVal it'll be 0 === 0 (no animation, stop).
  // In reality currentStyle should be 400
  unreadPropStyles: ?Array<Style> = null;

  // after checking for unreadPropStyles != null, we manually go set the
  // non-interpolating values (those that are a number, without a spring
  // config)
  clearUnreadPropStyle = (unreadPropStyles: Array<Style>): void => {
    let {
      currentStyles,
      currentVelocities,
      lastIdealStyles,
      lastIdealVelocities,
    } = this.state;

    let someDirty = false;
    for (let i = 0; i < unreadPropStyles.length; i++) {
      const unreadPropStyle = unreadPropStyles[i];
      let dirty = false;

      for (let key in unreadPropStyle) {
        if (!Object.prototype.hasOwnProperty.call(unreadPropStyle, key)) {
          continue;
        }

        const styleValue = unreadPropStyle[key];
        if (typeof styleValue === 'number') {
          if (!dirty) {
            dirty = true;
            someDirty = true;
            currentStyles[i] = { ...currentStyles[i] };
            currentVelocities[i] = { ...currentVelocities[i] };
            lastIdealStyles[i] = { ...lastIdealStyles[i] };
            lastIdealVelocities[i] = { ...lastIdealVelocities[i] };
          }
          currentStyles[i][key] = styleValue;
          currentVelocities[i][key] = 0;
          lastIdealStyles[i][key] = styleValue;
          lastIdealVelocities[i][key] = 0;
        }
      }
    }

    if (someDirty) {
      this.setState({
        currentStyles,
        currentVelocities,
        lastIdealStyles,
        lastIdealVelocities,
      });
    }
  };

  startAnimationIfNecessary = (): void => {
    if (this.unmounting || this.animationID != null) {
      return;
    }

    // TODO: when config is {a: 10} and dest is {a: 10} do we raf once and
    // call cb? No, otherwise accidental parent rerender causes cb trigger
    this.animationID = defaultRaf(timestamp => {
      // https://github.com/chenglou/react-motion/pull/420
      // > if execution passes the conditional if (this.unmounting), then
      // executes async defaultRaf and after that component unmounts and after
      // that the callback of defaultRaf is called, then setState will be called
      // on unmounted component.
      if (this.unmounting) {
        return;
      }

      const destStyles: Array<Style> = this.props.styles(
        this.state.lastIdealStyles,
      );

      // check if we need to animate in the first place
      if (
        shouldStopAnimationAll(
          this.state.currentStyles,
          destStyles,
          this.state.currentVelocities,
        )
      ) {
        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.accumulatedTime = 0;
        return;
      }

      const currentTime = timestamp || defaultNow();
      const timeDelta = currentTime - this.prevTime;
      this.prevTime = currentTime;
      this.accumulatedTime = this.accumulatedTime + timeDelta;
      // more than 10 frames? prolly switched browser tab. Restart
      if (this.accumulatedTime > msPerFrame * 10) {
        this.accumulatedTime = 0;
      }

      if (this.accumulatedTime === 0) {
        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.startAnimationIfNecessary();
        return;
      }

      let currentFrameCompletion =
        (this.accumulatedTime -
          Math.floor(this.accumulatedTime / msPerFrame) * msPerFrame) /
        msPerFrame;
      const framesToCatchUp = Math.floor(this.accumulatedTime / msPerFrame);

      let newLastIdealStyles = [];
      let newLastIdealVelocities = [];
      let newCurrentStyles = [];
      let newCurrentVelocities = [];

      for (let i = 0; i < destStyles.length; i++) {
        const destStyle = destStyles[i];
        let newCurrentStyle: PlainStyle = {};
        let newCurrentVelocity: Velocity = {};
        let newLastIdealStyle: PlainStyle = {};
        let newLastIdealVelocity: Velocity = {};

        for (let key in destStyle) {
          if (!Object.prototype.hasOwnProperty.call(destStyle, key)) {
            continue;
          }

          const styleValue = destStyle[key];
          if (typeof styleValue === 'number') {
            newCurrentStyle[key] = styleValue;
            newCurrentVelocity[key] = 0;
            newLastIdealStyle[key] = styleValue;
            newLastIdealVelocity[key] = 0;
          } else {
            let newLastIdealStyleValue = this.state.lastIdealStyles[i][key];
            let newLastIdealVelocityValue = this.state.lastIdealVelocities[i][
              key
            ];
            for (let j = 0; j < framesToCatchUp; j++) {
              [newLastIdealStyleValue, newLastIdealVelocityValue] = stepper(
                msPerFrame / 1000,
                newLastIdealStyleValue,
                newLastIdealVelocityValue,
                styleValue.val,
                styleValue.stiffness,
                styleValue.damping,
                styleValue.precision,
              );
            }
            const [nextIdealX, nextIdealV] = stepper(
              msPerFrame / 1000,
              newLastIdealStyleValue,
              newLastIdealVelocityValue,
              styleValue.val,
              styleValue.stiffness,
              styleValue.damping,
              styleValue.precision,
            );

            newCurrentStyle[key] =
              newLastIdealStyleValue +
              (nextIdealX - newLastIdealStyleValue) * currentFrameCompletion;
            newCurrentVelocity[key] =
              newLastIdealVelocityValue +
              (nextIdealV - newLastIdealVelocityValue) * currentFrameCompletion;
            newLastIdealStyle[key] = newLastIdealStyleValue;
            newLastIdealVelocity[key] = newLastIdealVelocityValue;
          }
        }

        newCurrentStyles[i] = newCurrentStyle;
        newCurrentVelocities[i] = newCurrentVelocity;
        newLastIdealStyles[i] = newLastIdealStyle;
        newLastIdealVelocities[i] = newLastIdealVelocity;
      }

      this.animationID = null;
      // the amount we're looped over above
      this.accumulatedTime -= framesToCatchUp * msPerFrame;

      this.setState({
        currentStyles: newCurrentStyles,
        currentVelocities: newCurrentVelocities,
        lastIdealStyles: newLastIdealStyles,
        lastIdealVelocities: newLastIdealVelocities,
      });

      this.unreadPropStyles = null;

      this.startAnimationIfNecessary();
    });
  };

  componentDidMount() {
    this.prevTime = defaultNow();
    this.startAnimationIfNecessary();
  }

  UNSAFE_componentWillReceiveProps(props: StaggeredProps) {
    if (this.unreadPropStyles != null) {
      // previous props haven't had the chance to be set yet; set them here
      this.clearUnreadPropStyle(this.unreadPropStyles);
    }

    this.unreadPropStyles = props.styles(this.state.lastIdealStyles);
    if (this.animationID == null) {
      this.prevTime = defaultNow();
      this.startAnimationIfNecessary();
    }
  }

  componentWillUnmount() {
    this.unmounting = true;
    if (this.animationID != null) {
      defaultRaf.cancel(this.animationID);
      this.animationID = null;
    }
  }

  render(): ReactElement {
    const renderedChildren = this.props.children(this.state.currentStyles);
    return renderedChildren && React.Children.only(renderedChildren);
  }
}


================================================
FILE: src/TransitionMotion.js
================================================
/* @flow */
import mapToZero from './mapToZero';
import stripStyle from './stripStyle';
import stepper from './stepper';
import mergeDiff from './mergeDiff';
import defaultNow from 'performance-now';
import defaultRaf from 'raf';
import shouldStopAnimation from './shouldStopAnimation';
import React from 'react';
import PropTypes from 'prop-types';

import type {
  ReactElement,
  PlainStyle,
  Velocity,
  TransitionStyle,
  TransitionPlainStyle,
  WillEnter,
  WillLeave,
  DidLeave,
  TransitionProps,
} from './Types';

const msPerFrame = 1000 / 60;

// the children function & (potential) styles function asks as param an
// Array<TransitionPlainStyle>, where each TransitionPlainStyle is of the format
// {key: string, data?: any, style: PlainStyle}. However, the way we keep
// internal states doesn't contain such a data structure (check the state and
// TransitionMotionState). So when children function and others ask for such
// data we need to generate them on the fly by combining mergedPropsStyles and
// currentStyles/lastIdealStyles
function rehydrateStyles(
  mergedPropsStyles: Array<TransitionStyle>,
  unreadPropStyles: ?Array<TransitionStyle>,
  plainStyles: Array<PlainStyle>,
): Array<TransitionPlainStyle> {
  // Copy the value to a `const` so that Flow understands that the const won't
  // change and will be non-nullable in the callback below.
  const cUnreadPropStyles = unreadPropStyles;
  if (cUnreadPropStyles == null) {
    return mergedPropsStyles.map((mergedPropsStyle, i) => ({
      key: mergedPropsStyle.key,
      data: mergedPropsStyle.data,
      style: plainStyles[i],
    }));
  }
  return mergedPropsStyles.map((mergedPropsStyle, i) => {
    for (let j = 0; j < cUnreadPropStyles.length; j++) {
      if (cUnreadPropStyles[j].key === mergedPropsStyle.key) {
        return {
          key: cUnreadPropStyles[j].key,
          data: cUnreadPropStyles[j].data,
          style: plainStyles[i],
        };
      }
    }
    return {
      key: mergedPropsStyle.key,
      data: mergedPropsStyle.data,
      style: plainStyles[i],
    };
  });
}

function shouldStopAnimationAll(
  currentStyles: Array<PlainStyle>,
  destStyles: Array<TransitionStyle>,
  currentVelocities: Array<Velocity>,
  mergedPropsStyles: Array<TransitionStyle>,
): boolean {
  if (mergedPropsStyles.length !== destStyles.length) {
    return false;
  }

  for (let i = 0; i < mergedPropsStyles.length; i++) {
    if (mergedPropsStyles[i].key !== destStyles[i].key) {
      return false;
    }
  }

  // we have the invariant that mergedPropsStyles and
  // currentStyles/currentVelocities/last* are synced in terms of cells, see
  // mergeAndSync comment for more info
  for (let i = 0; i < mergedPropsStyles.length; i++) {
    if (
      !shouldStopAnimation(
        currentStyles[i],
        destStyles[i].style,
        currentVelocities[i],
      )
    ) {
      return false;
    }
  }

  return true;
}

// core key merging logic

// things to do: say previously merged style is {a, b}, dest style (prop) is {b,
// c}, previous current (interpolating) style is {a, b}
// **invariant**: current[i] corresponds to merged[i] in terms of key

// steps:
// turn merged style into {a?, b, c}
//    add c, value of c is destStyles.c
//    maybe remove a, aka call willLeave(a), then merged is either {b, c} or {a, b, c}
// turn current (interpolating) style from {a, b} into {a?, b, c}
//    maybe remove a
//    certainly add c, value of c is willEnter(c)
// loop over merged and construct new current
// dest doesn't change, that's owner's
function mergeAndSync(
  willEnter: WillEnter,
  willLeave: WillLeave,
  didLeave: DidLeave,
  oldMergedPropsStyles: Array<TransitionStyle>,
  destStyles: Array<TransitionStyle>,
  oldCurrentStyles: Array<PlainStyle>,
  oldCurrentVelocities: Array<Velocity>,
  oldLastIdealStyles: Array<PlainStyle>,
  oldLastIdealVelocities: Array<Velocity>,
): [
  Array<TransitionStyle>,
  Array<PlainStyle>,
  Array<Velocity>,
  Array<PlainStyle>,
  Array<Velocity>,
] {
  const newMergedPropsStyles = mergeDiff(
    oldMergedPropsStyles,
    destStyles,
    (oldIndex, oldMergedPropsStyle) => {
      const leavingStyle = willLeave(oldMergedPropsStyle);
      if (leavingStyle == null) {
        didLeave({
          key: oldMergedPropsStyle.key,
          data: oldMergedPropsStyle.data,
        });
        return null;
      }
      if (
        shouldStopAnimation(
          oldCurrentStyles[oldIndex],
          leavingStyle,
          oldCurrentVelocities[oldIndex],
        )
      ) {
        didLeave({
          key: oldMergedPropsStyle.key,
          data: oldMergedPropsStyle.data,
        });
        return null;
      }
      return {
        key: oldMergedPropsStyle.key,
        data: oldMergedPropsStyle.data,
        style: leavingStyle,
      };
    },
  );

  let newCurrentStyles = [];
  let newCurrentVelocities = [];
  let newLastIdealStyles = [];
  let newLastIdealVelocities = [];
  for (let i = 0; i < newMergedPropsStyles.length; i++) {
    const newMergedPropsStyleCell = newMergedPropsStyles[i];
    let foundOldIndex = null;
    for (let j = 0; j < oldMergedPropsStyles.length; j++) {
      if (oldMergedPropsStyles[j].key === newMergedPropsStyleCell.key) {
        foundOldIndex = j;
        break;
      }
    }
    // TODO: key search code
    if (foundOldIndex == null) {
      const plainStyle = willEnter(newMergedPropsStyleCell);
      newCurrentStyles[i] = plainStyle;
      newLastIdealStyles[i] = plainStyle;

      const velocity = mapToZero(newMergedPropsStyleCell.style);
      newCurrentVelocities[i] = velocity;
      newLastIdealVelocities[i] = velocity;
    } else {
      newCurrentStyles[i] = oldCurrentStyles[foundOldIndex];
      newLastIdealStyles[i] = oldLastIdealStyles[foundOldIndex];
      newCurrentVelocities[i] = oldCurrentVelocities[foundOldIndex];
      newLastIdealVelocities[i] = oldLastIdealVelocities[foundOldIndex];
    }
  }

  return [
    newMergedPropsStyles,
    newCurrentStyles,
    newCurrentVelocities,
    newLastIdealStyles,
    newLastIdealVelocities,
  ];
}

type TransitionMotionDefaultProps = {
  willEnter: WillEnter,
  willLeave: WillLeave,
  didLeave: DidLeave,
};

type TransitionMotionState = {
  // list of styles, each containing interpolating values. Part of what's passed
  // to children function. Notice that this is
  // Array<ActualInterpolatingStyleObject>, without the wrapper that is {key: ...,
  // data: ... style: ActualInterpolatingStyleObject}. Only mergedPropsStyles
  // contains the key & data info (so that we only have a single source of truth
  // for these, and to save space). Check the comment for `rehydrateStyles` to
  // see how we regenerate the entirety of what's passed to children function
  currentStyles: Array<PlainStyle>,
  currentVelocities: Array<Velocity>,
  lastIdealStyles: Array<PlainStyle>,
  lastIdealVelocities: Array<Velocity>,
  // the array that keeps track of currently rendered stuff! Including stuff
  // that you've unmounted but that's still animating. This is where it lives
  mergedPropsStyles: Array<TransitionStyle>,
};

export default class TransitionMotion extends React.Component<
  TransitionProps,
  TransitionMotionState,
> {
  static propTypes = {
    defaultStyles: PropTypes.arrayOf(
      PropTypes.shape({
        key: PropTypes.string.isRequired,
        data: PropTypes.any,
        style: PropTypes.objectOf(PropTypes.number).isRequired,
      }),
    ),
    styles: PropTypes.oneOfType([
      PropTypes.func,
      PropTypes.arrayOf(
        PropTypes.shape({
          key: PropTypes.string.isRequired,
          data: PropTypes.any,
          style: PropTypes.objectOf(
            PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
          ).isRequired,
        }),
      ),
    ]).isRequired,
    children: PropTypes.func.isRequired,
    willEnter: PropTypes.func,
    willLeave: PropTypes.func,
    didLeave: PropTypes.func,
  };

  static defaultProps: TransitionMotionDefaultProps = {
    willEnter: styleThatEntered => stripStyle(styleThatEntered.style),
    // recall: returning null makes the current unmounting TransitionStyle
    // disappear immediately
    willLeave: () => null,
    didLeave: () => {},
  };

  unmounting: boolean = false;
  animationID: ?number = null;
  prevTime = 0;
  accumulatedTime = 0;
  // it's possible that currentStyle's value is stale: if props is immediately
  // changed from 0 to 400 to spring(0) again, the async currentStyle is still
  // at 0 (didn't have time to tick and interpolate even once). If we naively
  // compare currentStyle with destVal it'll be 0 === 0 (no animation, stop).
  // In reality currentStyle should be 400
  unreadPropStyles: ?Array<TransitionStyle> = null;

  constructor(props: TransitionProps) {
    super(props);
    this.state = this.defaultState();
  }

  defaultState(): TransitionMotionState {
    const {
      defaultStyles,
      styles,
      willEnter,
      willLeave,
      didLeave,
    } = this.props;
    const destStyles: Array<TransitionStyle> =
      typeof styles === 'function' ? styles(defaultStyles) : styles;

    // this is special. for the first time around, we don't have a comparison
    // between last (no last) and current merged props. we'll compute last so:
    // say default is {a, b} and styles (dest style) is {b, c}, we'll
    // fabricate last as {a, b}
    let oldMergedPropsStyles: Array<TransitionStyle>;
    if (defaultStyles == null) {
      oldMergedPropsStyles = destStyles;
    } else {
      oldMergedPropsStyles = (defaultStyles: any).map(defaultStyleCell => {
        // TODO: key search code
        for (let i = 0; i < destStyles.length; i++) {
          if (destStyles[i].key === defaultStyleCell.key) {
            return destStyles[i];
          }
        }
        return defaultStyleCell;
      });
    }
    const oldCurrentStyles =
      defaultStyles == null
        ? destStyles.map(s => stripStyle(s.style))
        : (defaultStyles: any).map(s => stripStyle(s.style));
    const oldCurrentVelocities =
      defaultStyles == null
        ? destStyles.map(s => mapToZero(s.style))
        : defaultStyles.map(s => mapToZero(s.style));
    const [
      mergedPropsStyles,
      currentStyles,
      currentVelocities,
      lastIdealStyles,
      lastIdealVelocities,
    ] = mergeAndSync(
      // Because this is an old-style createReactClass component, Flow doesn't
      // understand that the willEnter and willLeave props have default values
      // and will always be present.
      (willEnter: any),
      (willLeave: any),
      (didLeave: any),
      oldMergedPropsStyles,
      destStyles,
      oldCurrentStyles,
      oldCurrentVelocities,
      oldCurrentStyles, // oldLastIdealStyles really
      oldCurrentVelocities, // oldLastIdealVelocities really
    );

    return {
      currentStyles,
      currentVelocities,
      lastIdealStyles,
      lastIdealVelocities,
      mergedPropsStyles,
    };
  }

  // after checking for unreadPropStyles != null, we manually go set the
  // non-interpolating values (those that are a number, without a spring
  // config)
  clearUnreadPropStyle = (unreadPropStyles: Array<TransitionStyle>): void => {
    let [
      mergedPropsStyles,
      currentStyles,
      currentVelocities,
      lastIdealStyles,
      lastIdealVelocities,
    ] = mergeAndSync(
      (this.props.willEnter: any),
      (this.props.willLeave: any),
      (this.props.didLeave: any),
      this.state.mergedPropsStyles,
      unreadPropStyles,
      this.state.currentStyles,
      this.state.currentVelocities,
      this.state.lastIdealStyles,
      this.state.lastIdealVelocities,
    );

    for (let i = 0; i < unreadPropStyles.length; i++) {
      const unreadPropStyle = unreadPropStyles[i].style;
      let dirty = false;

      for (let key in unreadPropStyle) {
        if (!Object.prototype.hasOwnProperty.call(unreadPropStyle, key)) {
          continue;
        }

        const styleValue = unreadPropStyle[key];
        if (typeof styleValue === 'number') {
          if (!dirty) {
            dirty = true;
            currentStyles[i] = { ...currentStyles[i] };
            currentVelocities[i] = { ...currentVelocities[i] };
            lastIdealStyles[i] = { ...lastIdealStyles[i] };
            lastIdealVelocities[i] = { ...lastIdealVelocities[i] };
            mergedPropsStyles[i] = {
              key: mergedPropsStyles[i].key,
              data: mergedPropsStyles[i].data,
              style: { ...mergedPropsStyles[i].style },
            };
          }
          currentStyles[i][key] = styleValue;
          currentVelocities[i][key] = 0;
          lastIdealStyles[i][key] = styleValue;
          lastIdealVelocities[i][key] = 0;
          mergedPropsStyles[i].style[key] = styleValue;
        }
      }
    }

    // unlike the other 2 components, we can't detect staleness and optionally
    // opt out of setState here. each style object's data might contain new
    // stuff we're not/cannot compare
    this.setState({
      currentStyles,
      currentVelocities,
      mergedPropsStyles,
      lastIdealStyles,
      lastIdealVelocities,
    });
  };

  startAnimationIfNecessary = (): void => {
    if (this.unmounting || this.animationID != null) {
      return;
    }

    // TODO: when config is {a: 10} and dest is {a: 10} do we raf once and
    // call cb? No, otherwise accidental parent rerender causes cb trigger
    this.animationID = defaultRaf(timestamp => {
      // https://github.com/chenglou/react-motion/pull/420
      // > if execution passes the conditional if (this.unmounting), then
      // executes async defaultRaf and after that component unmounts and after
      // that the callback of defaultRaf is called, then setState will be called
      // on unmounted component.
      if (this.unmounting) {
        return;
      }

      const propStyles = this.props.styles;
      let destStyles: Array<TransitionStyle> =
        typeof propStyles === 'function'
          ? propStyles(
              rehydrateStyles(
                this.state.mergedPropsStyles,
                this.unreadPropStyles,
                this.state.lastIdealStyles,
              ),
            )
          : propStyles;

      // check if we need to animate in the first place
      if (
        shouldStopAnimationAll(
          this.state.currentStyles,
          destStyles,
          this.state.currentVelocities,
          this.state.mergedPropsStyles,
        )
      ) {
        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.accumulatedTime = 0;
        return;
      }

      const currentTime = timestamp || defaultNow();
      const timeDelta = currentTime - this.prevTime;
      this.prevTime = currentTime;
      this.accumulatedTime = this.accumulatedTime + timeDelta;
      // more than 10 frames? prolly switched browser tab. Restart
      if (this.accumulatedTime > msPerFrame * 10) {
        this.accumulatedTime = 0;
      }

      if (this.accumulatedTime === 0) {
        // no need to cancel animationID here; shouldn't have any in flight
        this.animationID = null;
        this.startAnimationIfNecessary();
        return;
      }

      let currentFrameCompletion =
        (this.accumulatedTime -
          Math.floor(this.accumulatedTime / msPerFrame) * msPerFrame) /
        msPerFrame;
      const framesToCatchUp = Math.floor(this.accumulatedTime / msPerFrame);

      let [
        newMergedPropsStyles,
        newCurrentStyles,
        newCurrentVelocities,
        newLastIdealStyles,
        newLastIdealVelocities,
      ] = mergeAndSync(
        (this.props.willEnter: any),
        (this.props.willLeave: any),
        (this.props.didLeave: any),
        this.state.mergedPropsStyles,
        destStyles,
        this.state.currentStyles,
        this.state.currentVelocities,
        this.state.lastIdealStyles,
        this.state.lastIdealVelocities,
      );
      for (let i = 0; i < newMergedPropsStyles.length; i++) {
        const newMergedPropsStyle = newMergedPropsStyles[i].style;
        let newCurrentStyle: PlainStyle = {};
        let newCurrentVelocity: Velocity = {};
        let newLastIdealStyle: PlainStyle = {};
        let newLastIdealVelocity: Velocity = {};

        for (let key in newMergedPropsStyle) {
          if (!Object.prototype.hasOwnProperty.call(newMergedPropsStyle, key)) {
            continue;
          }

          const styleValue = newMergedPropsStyle[key];
          if (typeof styleValue === 'number') {
            newCurrentStyle[key] = styleValue;
            newCurrentVelocity[key] = 0;
            newLastIdealStyle[key] = styleValue;
            newLastIdealVelocity[key] = 0;
          } else {
            let newLastIdealStyleValue = newLastIdealStyles[i][key];
            let newLastIdealVelocityValue = newLastIdealVelocities[i][key];
            for (let j = 0; j < framesToCatchUp; j++) {
              [newLastIdealStyleValue, newLastIdealVelocityValue] = stepper(
                msPerFrame / 1000,
                newLastIdealStyleValue,
                newLastIdealVelocityValue,
                styleValue.val,
                styleValue.stiffness,
                styleValue.damping,
                styleValue.precision,
              );
            }
            const [nextIdealX, nextIdealV] = stepper(
              msPerFrame / 1000,
              newLastIdealStyleValue,
              newLastIdealVelocityValue,
              styleValue.val,
              styleValue.stiffness,
              styleValue.damping,
              styleValue.precision,
            );

            newCurrentStyle[key] =
              newLastIdealStyleValue +
              (nextIdealX - newLastIdealStyleValue) * currentFrameCompletion;
            newCurrentVelocity[key] =
              newLastIdealVelocityValue +
              (nextIdealV - newLastIdealVelocityValue) * currentFrameCompletion;
            newLastIdealStyle[key] = newLastIdealStyleValue;
            newLastIdealVelocity[key] = newLastIdealVelocityValue;
          }
        }

        newLastIdealStyles[i] = newLastIdealStyle;
        newLastIdealVelocities[i] = newLastIdealVelocity;
        newCurrentStyles[i] = newCurrentStyle;
        newCurrentVelocities[i] = newCurrentVelocity;
      }

      this.animationID = null;
      // the amount we're looped over above
      this.accumulatedTime -= framesToCatchUp * msPerFrame;

      this.setState({
        currentStyles: newCurrentStyles,
        currentVelocities: newCurrentVelocities,
        lastIdealStyles: newLastIdealStyles,
        lastIdealVelocities: newLastIdealVelocities,
        mergedPropsStyles: newMergedPropsStyles,
      });

      this.unreadPropStyles = null;

      this.startAnimationIfNecessary();
    });
  };

  componentDidMount() {
    this.prevTime = defaultNow();
    this.startAnimationIfNecessary();
  }

  UNSAFE_componentWillReceiveProps(props: TransitionProps) {
    if (this.unreadPropStyles) {
      // previous props haven't had the chance to be set yet; set them here
      this.clearUnreadPropStyle(this.unreadPropStyles);
    }

    const styles = props.styles;
    if (typeof styles === 'function') {
      this.unreadPropStyles = styles(
        rehydrateStyles(
          this.state.mergedPropsStyles,
          this.unreadPropStyles,
          this.state.lastIdealStyles,
        ),
      );
    } else {
      this.unreadPropStyles = styles;
    }

    if (this.animationID == null) {
      this.prevTime = defaultNow();
      this.startAnimationIfNecessary();
    }
  }

  componentWillUnmount() {
    this.unmounting = true;
    if (this.animationID != null) {
      defaultRaf.cancel(this.animationID);
      this.animationID = null;
    }
  }

  render(): ReactElement {
    const hydratedStyles = rehydrateStyles(
      this.state.mergedPropsStyles,
      this.unreadPropStyles,
      this.state.currentStyles,
    );
    const renderedChildren = this.props.children(hydratedStyles);
    return renderedChildren && React.Children.only(renderedChildren);
  }
}


================================================
FILE: src/Types.js
================================================
/* @flow */

// Babel 5.x doesn't support type parameters, so we make this alias here out of
// Babel's sight.
/* eslint-disable spaced-comment, no-undef */
/*::
import type {Element} from 'react';
export type ReactElement = Element<*>;
*/

// === basic reused types ===
// type of the second parameter of `spring(val, config)` all fields are optional
export type SpringHelperConfig = {
  stiffness?: number,
  damping?: number,
  precision?: number,
};
// the object returned by `spring(value, yourConfig)`. For internal usage only!
export type OpaqueConfig = {
  val: number,
  stiffness: number,
  damping: number,
  precision: number,
};
// your typical style object given in props. Maps to a number or a spring config
export type Style = { [key: string]: number | OpaqueConfig };
// the interpolating style object, with the same keys as the above Style object,
// with the values mapped to numbers, naturally
export type PlainStyle = { [key: string]: number };
// internal velocity object. Similar to PlainStyle, but whose numbers represent
// speed. Might be exposed one day.
export type Velocity = { [key: string]: number };

// === Motion ===
export type MotionProps = {
  defaultStyle?: PlainStyle,
  style: Style,
  children: (interpolatedStyle: PlainStyle) => ReactElement,
  onRest?: () => void,
};

// === StaggeredMotion ===
export type StaggeredProps = {
  defaultStyles?: Array<PlainStyle>,
  styles: (previousInterpolatedStyles: ?Array<PlainStyle>) => Array<Style>,
  children: (interpolatedStyles: Array<PlainStyle>) => ReactElement,
};

// === TransitionMotion ===
export type TransitionStyle = {
  key: string, // unique ID to identify component across render animations
  data?: any, // optional data you want to carry along the style, e.g. itemText
  style: Style, // actual style you're passing
};
export type TransitionPlainStyle = {
  key: string,
  data?: any,
  // same as TransitionStyle, passed as argument to style/children function
  style: PlainStyle,
};
export type WillEnter = (styleThatEntered: TransitionStyle) => PlainStyle;
export type WillLeave = (styleThatLeft: TransitionStyle) => ?Style;
export type DidLeave = (styleThatLeft: { key: string, data?: any }) => void;

export type TransitionProps = {
  defaultStyles?: Array<TransitionPlainStyle>,
  styles:
    | Array<TransitionStyle>
    | ((
        previousInterpolatedStyles: ?Array<TransitionPlainStyle>,
      ) => Array<TransitionStyle>),
  children: (interpolatedStyles: Array<TransitionPlainStyle>) => ReactElement,
  willEnter?: WillEnter,
  willLeave?: WillLeave,
  didLeave?: DidLeave,
};


================================================
FILE: src/mapToZero.js
================================================
/* @flow */
import type { PlainStyle, Style } from './Types';

// currently used to initiate the velocity style object to 0
export default function mapToZero(obj: Style | PlainStyle): PlainStyle {
  let ret = {};
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      ret[key] = 0;
    }
  }
  return ret;
}


================================================
FILE: src/mergeDiff.js
================================================
/* @flow */
import type { TransitionStyle } from './Types';

// core keys merging algorithm. If previous render's keys are [a, b], and the
// next render's [c, b, d], what's the final merged keys and ordering?

// - c and a must both be before b
// - b before d
// - ordering between a and c ambiguous

// this reduces to merging two partially ordered lists (e.g. lists where not
// every item has a definite ordering, like comparing a and c above). For the
// ambiguous ordering we deterministically choose to place the next render's
// item after the previous'; so c after a

// this is called a topological sorting. Except the existing algorithms don't
// work well with js bc of the amount of allocation, and isn't optimized for our
// current use-case bc the runtime is linear in terms of edges (see wiki for
// meaning), which is huge when two lists have many common elements
export default function mergeDiff(
  prev: Array<TransitionStyle>,
  next: Array<TransitionStyle>,
  onRemove: (
    prevIndex: number,
    prevStyleCell: TransitionStyle,
  ) => ?TransitionStyle,
): Array<TransitionStyle> {
  // bookkeeping for easier access of a key's index below. This is 2 allocations +
  // potentially triggering chrome hash map mode for objs (so it might be faster
  // to loop through and find a key's index each time), but I no longer care
  let prevKeyIndex: { [key: string]: number } = {};
  for (let i = 0; i < prev.length; i++) {
    prevKeyIndex[prev[i].key] = i;
  }
  let nextKeyIndex: { [key: string]: number } = {};
  for (let i = 0; i < next.length; i++) {
    nextKeyIndex[next[i].key] = i;
  }

  // first, an overly elaborate way of merging prev and next, eliminating
  // duplicates (in terms of keys). If there's dupe, keep the item in next).
  // This way of writing it saves allocations
  let ret = [];
  for (let i = 0; i < next.length; i++) {
    ret[i] = next[i];
  }
  for (let i = 0; i < prev.length; i++) {
    if (!Object.prototype.hasOwnProperty.call(nextKeyIndex, prev[i].key)) {
      // this is called my TM's `mergeAndSync`, which calls willLeave. We don't
      // merge in keys that the user desires to kill
      const fill = onRemove(i, prev[i]);
      if (fill != null) {
        ret.push(fill);
      }
    }
  }

  // now all the items all present. Core sorting logic to have the right order
  return ret.sort((a, b) => {
    const nextOrderA = nextKeyIndex[a.key];
    const nextOrderB = nextKeyIndex[b.key];
    const prevOrderA = prevKeyIndex[a.key];
    const prevOrderB = prevKeyIndex[b.key];

    if (nextOrderA != null && nextOrderB != null) {
      // both keys in next
      return nextKeyIndex[a.key] - nextKeyIndex[b.key];
    } else if (prevOrderA != null && prevOrderB != null) {
      // both keys in prev
      return prevKeyIndex[a.key] - prevKeyIndex[b.key];
    } else if (nextOrderA != null) {
      // key a in next, key b in prev

      // how to determine the order between a and b? We find a "pivot" (term
      // abuse), a key present in both prev and next, that is sandwiched between
      // a and b. In the context of our above example, if we're comparing a and
      // d, b's (the only) pivot
      for (let i = 0; i < next.length; i++) {
        const pivot = next[i].key;
        if (!Object.prototype.hasOwnProperty.call(prevKeyIndex, pivot)) {
          continue;
        }

        if (
          nextOrderA < nextKeyIndex[pivot] &&
          prevOrderB > prevKeyIndex[pivot]
        ) {
          return -1;
        } else if (
          nextOrderA > nextKeyIndex[pivot] &&
          prevOrderB < prevKeyIndex[pivot]
        ) {
          return 1;
        }
      }
      // pluggable. default to: next bigger than prev
      return 1;
    }
    // prevOrderA, nextOrderB
    for (let i = 0; i < next.length; i++) {
      const pivot = next[i].key;
      if (!Object.prototype.hasOwnProperty.call(prevKeyIndex, pivot)) {
        continue;
      }
      if (
        nextOrderB < nextKeyIndex[pivot] &&
        prevOrderA > prevKeyIndex[pivot]
      ) {
        return 1;
      } else if (
        nextOrderB > nextKeyIndex[pivot] &&
        prevOrderA < prevKeyIndex[pivot]
      ) {
        return -1;
      }
    }
    // pluggable. default to: next bigger than prev
    return -1;
  });
}


================================================
FILE: src/presets.js
================================================
/* @flow */
export default {
  noWobble: { stiffness: 170, damping: 26 }, // the default, if nothing provided
  gentle: { stiffness: 120, damping: 14 },
  wobbly: { stiffness: 180, damping: 12 },
  stiff: { stiffness: 210, damping: 20 },
};


================================================
FILE: src/react-motion.js
================================================
/* @flow */
export { default as Motion } from './Motion';
export { default as StaggeredMotion } from './StaggeredMotion';
export { default as TransitionMotion } from './TransitionMotion';
export { default as spring } from './spring';
export { default as presets } from './presets';
export { default as stripStyle } from './stripStyle';

// deprecated, dummy warning function
export { default as reorderKeys } from './reorderKeys';


================================================
FILE: src/reorderKeys.js
================================================
/* @flow */

let hasWarned = false;
export default function reorderKeys() {
  if (process.env.NODE_ENV === 'development') {
    if (!hasWarned) {
      hasWarned = true;
      console.error(
        "`reorderKeys` has been removed, since it is no longer needed for TransitionMotion's new styles array API.",
      );
    }
  }
}


================================================
FILE: src/shouldStopAnimation.js
================================================
/* @flow */
import type { PlainStyle, Style, Velocity } from './Types';

// usage assumption: currentStyle values have already been rendered but it says
// nothing of whether currentStyle is stale (see unreadPropStyle)
export default function shouldStopAnimation(
  currentStyle: PlainStyle,
  style: Style,
  currentVelocity: Velocity,
): boolean {
  for (let key in style) {
    if (!Object.prototype.hasOwnProperty.call(style, key)) {
      continue;
    }

    if (currentVelocity[key] !== 0) {
      return false;
    }

    const styleValue =
      typeof style[key] === 'number' ? style[key] : style[key].val;
    // stepper will have already taken care of rounding precision errors, so
    // won't have such thing as 0.9999 !=== 1
    if (currentStyle[key] !== styleValue) {
      return false;
    }
  }

  return true;
}


================================================
FILE: src/spring.js
================================================
/* @flow */
import presets from './presets';
import type { OpaqueConfig, SpringHelperConfig } from './Types';

const defaultConfig = {
  ...presets.noWobble,
  precision: 0.01,
};

export default function spring(
  val: number,
  config?: SpringHelperConfig,
): OpaqueConfig {
  return { ...defaultConfig, ...config, val };
}


================================================
FILE: src/stepper.js
================================================
/* @flow */

// stepper is used a lot. Saves allocation to return the same array wrapper.
// This is fine and danger-free against mutations because the callsite
// immediately destructures it and gets the numbers inside without passing the
// array reference around.
let reusedTuple: [number, number] = [0, 0];
export default function stepper(
  secondPerFrame: number,
  x: number,
  v: number,
  destX: number,
  k: number,
  b: number,
  precision: number,
): [number, number] {
  // Spring stiffness, in kg / s^2

  // for animations, destX is really spring length (spring at rest). initial
  // position is considered as the stretched/compressed position of a spring
  const Fspring = -k * (x - destX);

  // Damping, in kg / s
  const Fdamper = -b * v;

  // usually we put mass here, but for animation purposes, specifying mass is a
  // bit redundant. you could simply adjust k and b accordingly
  // let a = (Fspring + Fdamper) / mass;
  const a = Fspring + Fdamper;

  const newV = v + a * secondPerFrame;
  const newX = x + newV * secondPerFrame;

  if (Math.abs(newV) < precision && Math.abs(newX - destX) < precision) {
    reusedTuple[0] = destX;
    reusedTuple[1] = 0;
    return reusedTuple;
  }

  reusedTuple[0] = newX;
  reusedTuple[1] = newV;
  return reusedTuple;
}


================================================
FILE: src/stripStyle.js
================================================
/* @flow */
// turn {x: {val: 1, stiffness: 1, damping: 2}, y: 2} generated by
// `{x: spring(1, {stiffness: 1, damping: 2}), y: 2}` into {x: 1, y: 2}

import type { Style, PlainStyle } from './Types';

export default function stripStyle(style: Style): PlainStyle {
  let ret = {};
  for (const key in style) {
    if (!Object.prototype.hasOwnProperty.call(style, key)) {
      continue;
    }
    ret[key] = typeof style[key] === 'number' ? style[key] : style[key].val;
  }
  return ret;
}


================================================
FILE: test/Motion-test.js
================================================
/* eslint-disable class-methods-use-this */
import React from 'react';
import {spring} from '../src/react-motion';
import createMockRaf from './createMockRaf';
import TestUtils from 'react-dom/test-utils';

const {createSpy} = global.jasmine;

const injector = require('inject-loader!../src/Motion');

// temporarily putting the animation loop test here
// TODO: put it in the correct file
describe('animation loop', () => {
  let Motion;
  let mockRaf;

  beforeEach(() => {
    mockRaf = createMockRaf();
    Motion = injector({
      raf: mockRaf.raf,
      'performance-now': mockRaf.now,
    }).default;
  });

  it('should interpolate correctly when the timer is perfect', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{a: 0}} style={{a: spring(10)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    mockRaf.step(5);
    expect(count).toEqual([
      0,
      0.4722222222222222,
      1.1897376543209877,
      2.0123698988340193,
      2.8557218143909084,
      3.670989925304686,
    ]);
  });

  it('should work with negative numbers', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{a: -10}} style={{a: spring(-100)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(5);
    expect(count).toEqual([
      -10,
      -14.25,
      -20.70763888888889,
      -28.11132908950617,
      -35.70149632951818,
      -43.038909327742175,
    ]);
  });

  it('should interpolate correctly when the timer is imperfect', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{a: 0}} style={{a: spring(10)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    mockRaf.step(10, 0);
    // 0 accumulatedTime, bail out of recalc & render
    expect(count).toEqual([0]);

    mockRaf.step(3, 0.1);
    expect(count).toEqual([
      0,
      // notice the numbers are all very close together
      0.002833333333333333,
      0.005666666666666666,
      0.0085,
    ]);
    // interval too large; bail
    mockRaf.step(10, 999);
    expect(count).toEqual([
      0,
      0.002833333333333333,
      0.005666666666666666,
      0.0085,
    ]);
    // more than one theoretical frame passed, each tick
    mockRaf.step(2, 36);
    expect(count).toEqual([
      0,
      0.002833333333333333,
      0.005666666666666666,
      0.0085,
      1.3213588134430725,
      3.116607609883317,
    ]);
  });
});

describe('Motion', () => {
  let Motion;
  let mockRaf;

  beforeEach(() => {
    mockRaf = createMockRaf();
    Motion = injector({
      raf: mockRaf.raf,
      'performance-now': mockRaf.now,
    }).default;
  });

  it('should allow returning null from children function', () => {
    class App extends React.Component {
      render() {
        // shouldn't throw here
        return <Motion style={{a: 0}}>{() => null}</Motion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
  });

  it('should not throw on unmount', () => {
    spyOn(console, 'error');
    let kill = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          kill: false,
        };
      }
      componentWillMount() {
        kill = () => this.setState({kill: true});
      }
      render() {
        return this.state.kill
          ? null
          : <Motion defaultStyle={{a: 0}} style={{a: spring(10)}}>{() => null}</Motion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
    mockRaf.step(2);
    kill();
    mockRaf.step(3);
    expect(console.error).not.toHaveBeenCalled();
  });

  it('should allow a defaultStyle', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{a: 0}} style={{a: spring(10)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    mockRaf.step(4);
    expect(count).toEqual([
      0,
      0.4722222222222222,
      1.1897376543209877,
      2.0123698988340193,
      2.8557218143909084,
    ]);
  });

  it('should accept different spring configs', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion
              defaultStyle={{a: 0}}
              style={{a: spring(10, {stiffness: 100, damping: 50, precision: 16})}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(99);
    expect(count).toEqual([
      0,
      0.2777777777777778,
      0.5941358024691358,
      0.9081361454046639,
      1.213021309632678,
      1.5079182450697726,
      1.7929588941684615,
      2.0684390330691236,
      10,
    ]);
  });

  it('should interpolate many values', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion
            defaultStyle={{a: 0, b: 10}}
            style={{a: spring(10), b: spring(410)}}>
            {({a, b}) => {
              count.push([a, b]);
              return null;
            }}
          </Motion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[0, 10]]);
    mockRaf.step(4);
    expect(count).toEqual([
      [0, 10],
      [0.4722222222222222, 28.888888888888886],
      [1.1897376543209877, 57.589506172839506],
      [2.0123698988340193, 90.49479595336075],
      [2.8557218143909084, 124.22887257563633],
    ]);
  });

  it('should work with nested Motions', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{owner: 0}} style={{owner: spring(10)}}>
            {({owner}) => {
              count.push(owner);
              return (
                <Motion defaultStyle={{child: 10}} style={{child: spring(400)}}>
                  {({child}) => {
                    count.push(child);
                    return null;
                  }}
                </Motion>
              );
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0, 10]);
    mockRaf.step();
    expect(count).toEqual([
      0,
      10,
      28.416666666666668, // child
      0.4722222222222222, // owner
      28.416666666666668, // child
    ]);
    mockRaf.step(2);
    expect(count).toEqual([
      0,
      10,
      28.416666666666668,
      0.4722222222222222,
      28.416666666666668,

      56.39976851851852, // child
      1.1897376543209877, // owner
      56.39976851851852, // child

      88.48242605452674, // child
      2.0123698988340193, // owner
      88.48242605452674, // child
    ]);
  });

  it('should reach destination value', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <Motion defaultStyle={{a: 0}} style={{a: spring(400)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    mockRaf.step(111);
    expect(count.slice(0, 5)).toEqual([
      0,
      18.888888888888886,
      47.589506172839506,
      80.49479595336075,
      114.22887257563633,
    ]);
    expect(count.length).toBe(91);
    expect(count[count.length - 1]).toEqual(400);
  });

  it('should support jumping to value', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          p: false,
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <Motion style={{a: this.state.p ? 400 : spring(0)}}>
            {({a}) => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    setState({p: true});
    expect(count).toEqual([
      0,
      0, // this new 0 comes from owner update, causing Motion to re-render
    ]);
    mockRaf.step(10);
    // jumped to end, will only have two renders no matter how much we step
    expect(count).toEqual([
      0,
      0,
      400,
    ]);
    setState({p: false});
    mockRaf.step(3);
    expect(count).toEqual([
      0,
      0,
      400,
      400, // redundant 0 comes from owner update again
      381.1111111111111,
      352.4104938271605,
      319.5052040466392,
    ]);
  });

  it('should call onRest at the end of an animation', () => {
    const onRest = createSpy('onRest');
    let result = 0;

    class App extends React.Component {
      render() {
        return (
          <Motion
            defaultStyle={{a: 0}}
            style={{a: spring(5, {stiffness: 380, damping: 18, precision: 1})}}
            onRest={onRest}
          >
            {
              ({a}) => {
                result = a;
                return null;
              }
            }
          </Motion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(22);

    expect(result).toEqual(5);
    expect(onRest.calls.count()).toEqual(1);
  });


  it('should not call onRest if an animation is still in progress', () => {
    const onRest = createSpy('onRest');
    let resultA = 0;
    let resultB = 0;

    class App extends React.Component {
      render() {
        return (
          <Motion
            defaultStyle={{a: 0, b: 0}}
            style={{
              a: spring(5, {stiffness: 380, damping: 18, precision: 1}),
              b: spring(500, {stiffness: 380, damping: 18, precision: 1}),
            }}
            onRest={onRest}
          >
            {
              ({a, b}) => {
                resultA = a;
                resultB = b;
                return null;
              }
            }
          </Motion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(22);

    expect(resultA).toEqual(5);
    expect(resultB).not.toEqual(500);
    expect(onRest).not.toHaveBeenCalled();
  });


  it('should not call onRest unless an animation occurred', () => {
    const onRest = createSpy('onRest');

    let setState;

    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          a: spring(0),
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <Motion
            defaultStyle={{a: 0}}
            style={{a: this.state.a}}
            onRest={onRest}
          >
            {() => null}
          </Motion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);
    mockRaf.step();
    setState({a: 50});
    mockRaf.step();

    expect(onRest).not.toHaveBeenCalled();
  });

  it('should behave well when many owner updates come in-between rAFs', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          a: spring(0),
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <Motion style={this.state}>
            {a => {
              count.push(a);
              return null;
            }}
          </Motion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([{a: 0}]);
    setState({a: 400});
    setState({a: spring(100)});
    mockRaf.step(2);
    setState({a: spring(400)});
    mockRaf.step(2);
    expect(count).toEqual([
      {a: 0},
      {a: 0}, // this new 0 comes from owner update, causing Motion to re-render
      {a: 400},
      {a: 385.8333333333333},
      {a: 364.3078703703703},
      {a: 364.3078703703703},
      {a: 353.79556970164606},
      {a: 350.02047519790233},
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(85);
    setState({a: spring(400)});
    // make sure we're still updating children even if there's nothing to interp
    expect(count.length).toBe(86);
  });
});


================================================
FILE: test/StaggeredMotion-test.js
================================================
/* eslint-disable class-methods-use-this */
import React from 'react';
import {spring} from '../src/react-motion';
import createMockRaf from './createMockRaf';
import TestUtils from 'react-dom/test-utils';

const injector = require('inject-loader!../src/StaggeredMotion');

describe('StaggeredMotion', () => {
  let StaggeredMotion;
  let mockRaf;

  beforeEach(() => {
    mockRaf = createMockRaf();
    StaggeredMotion = injector({
      raf: mockRaf.raf,
      'performance-now': mockRaf.now,
    }).default;
  });

  it('should allow returning null from children function', () => {
    class App extends React.Component {
      render() {
        // shouldn't throw here
        return (
          <StaggeredMotion styles={() => [{a: 0}]}>
            {() => null}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);
  });

  it('should not throw on unmount', () => {
    spyOn(console, 'error');
    let kill = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          kill: false,
        };
      }
      componentWillMount() {
        kill = () => this.setState({kill: true});
      }
      render() {
        return this.state.kill
          ? null
          : <StaggeredMotion defaultStyles={[{a: 0}]} styles={() => [{a: spring(10)}]}>
              {() => null}
            </StaggeredMotion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
    mockRaf.step(2);
    kill();
    mockRaf.step(3);
    expect(console.error).not.toHaveBeenCalled();
  });

  it('should allow a defaultStyles', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <StaggeredMotion
            defaultStyles={[{a: 0}]}
            styles={() => [{a: spring(10)}]}>
            {([{a}]) => {
              count.push(a);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    mockRaf.step(4);
    expect(count).toEqual([
      0,
      0.4722222222222222,
      1.1897376543209877,
      2.0123698988340193,
      2.8557218143909084,
    ]);
  });

  it('should accept different spring configs', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <StaggeredMotion
            defaultStyles={[{a: 0}]}
            styles={() => [{a: spring(10, {stiffness: 100, damping: 50, precision: 16})}]}>
            {([{a}]) => {
              count.push(a);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(99);
    expect(count).toEqual([
      0,
      0.2777777777777778,
      0.5941358024691358,
      0.9081361454046639,
      1.213021309632678,
      1.5079182450697726,
      1.7929588941684615,
      2.0684390330691236,
      10,
    ]);
  });

  it('should interpolate many values while staggering', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <StaggeredMotion
            defaultStyles={[{a: 0, b: 10}, {a: 0, b: 10}]}
            styles={prevStyles => {
              return prevStyles.map((_, i) => i === 0
                ? {a: spring(10), b: spring(410)}
                : {a: spring(prevStyles[i - 1].a), b: spring(prevStyles[i - 1].b)});
            }}>
            {([{a, b}, {a: a2, b: b2}]) => {
              count.push([a, b, a2, b2]);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[0, 10, 0, 10]]);
    mockRaf.step(4);
    expect(count).toEqual([
      [0, 10, 0, 10],
      [0.4722222222222222, 28.888888888888886, 0, 10],
      [1.1897376543209877, 57.589506172839506, 0.02229938271604938, 10.891975308641975],
      [2.0123698988340193, 90.49479595336075, 0.09006472908093276, 13.602589163237312],
      [2.8557218143909084, 124.22887257563633, 0.18039409126848038, 17.215763650739216],
    ]);
  });

  it('should work with nested Motions', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <StaggeredMotion defaultStyles={[{owner: 0}]} styles={() => [{owner: spring(10)}]}>
            {([{owner}]) => {
              count.push(owner);
              return (
                <StaggeredMotion defaultStyles={[{child: 10}]} styles={() => [{child: spring(400)}]}>
                  {([{child}]) => {
                    count.push(child);
                    return null;
                  }}
                </StaggeredMotion>
              );
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0, 10]);
    mockRaf.step();
    expect(count).toEqual([
      0,
      10,
      28.416666666666668, // child
      0.4722222222222222, // owner
      28.416666666666668, // child
    ]);
    mockRaf.step(2);
    expect(count).toEqual([
      0,
      10,
      28.416666666666668,
      0.4722222222222222,
      28.416666666666668,

      56.39976851851852, // child
      1.1897376543209877, // owner
      56.39976851851852, // child

      88.48242605452674, // child
      2.0123698988340193, // owner
      88.48242605452674, // child
    ]);
  });

  // TODO: should animate one last time to reach true destination
  // maybe shouldStopAnimation logic has a flaw
  it('should reach destination value', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <StaggeredMotion
            defaultStyles={[{a: 0, b: 10}, {a: 0, b: 10}]}
            styles={prevStyles => {
              return prevStyles.map((_, i) => i === 0
                ? {a: spring(10), b: spring(410)}
                : {a: spring(prevStyles[i - 1].a), b: spring(prevStyles[i - 1].b)});
            }}>
            {([{a, b}, {a: a2, b: b2}]) => {
              count.push([a, b, a2, b2]);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[0, 10, 0, 10]]);
    mockRaf.step(111);
    expect(count.slice(0, 5)).toEqual([
      [0, 10, 0, 10],
      [0.4722222222222222, 28.888888888888886, 0, 10],
      [1.1897376543209877, 57.589506172839506, 0.02229938271604938, 10.891975308641975],
      [2.0123698988340193, 90.49479595336075, 0.09006472908093276, 13.602589163237312],
      [2.8557218143909084, 124.22887257563633, 0.18039409126848038, 17.215763650739216],
    ]);
    expect(count.length).toBe(111);
    expect(count[count.length - 1]).toEqual([10, 410, 10, 410]);
  });

  it('should support jumping to value', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          p: false,
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <StaggeredMotion styles={() => [{a: this.state.p ? 400 : spring(0)}]}>
            {([{a}]) => {
              count.push(a);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    setState({p: true});
    expect(count).toEqual([
      0,
      0, // this new 0 comes from owner update, causing StaggeredMotion to re-render
    ]);
    mockRaf.step(10);
    // jumped to end, will only have two renders no matter how much we step
    expect(count).toEqual([
      0,
      0,
      400,
    ]);
    setState({p: false});
    mockRaf.step(3);
    expect(count).toEqual([
      0,
      0,
      400,
      400, // redundant 0 comes from owner update again
      381.1111111111111,
      352.4104938271605,
      319.5052040466392,
    ]);
  });

  it('should behave well when many owner updates come in-between rAFs', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          a: spring(0),
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <StaggeredMotion styles={() => [this.state]}>
            {([a]) => {
              count.push(a);
              return null;
            }}
          </StaggeredMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([{a: 0}]);
    setState({a: 400});
    setState({a: spring(100)});
    mockRaf.step(2);
    setState({a: spring(400)});
    mockRaf.step(2);
    expect(count).toEqual([
      {a: 0},
      {a: 0}, // this new 0 comes from owner update, causing StaggeredMotion to re-render
      {a: 400},
      {a: 385.8333333333333},
      {a: 364.3078703703703},
      {a: 364.3078703703703},
      {a: 353.79556970164606},
      {a: 350.02047519790233},
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(85);
    setState({a: spring(400)});
    // make sure we're still updating children even if there's nothing to interp
    expect(count.length).toBe(86);
  });
});


================================================
FILE: test/TransitionMotion-test.js
================================================
/* eslint-disable class-methods-use-this */
import React from 'react';
import {spring} from '../src/react-motion';
import createMockRaf from './createMockRaf';
import TestUtils from 'react-dom/test-utils';

const injector = require('inject-loader!../src/TransitionMotion');

describe('TransitionMotion', () => {
  let TransitionMotion;
  let mockRaf;

  beforeEach(() => {
    mockRaf = createMockRaf();
    TransitionMotion = injector({
      raf: mockRaf.raf,
      'performance-now': mockRaf.now,
    }).default;
  });

  it('should allow returning null from children function', () => {
    class App extends React.Component {
      render() {
        // shouldn't throw here
        return <TransitionMotion styles={[{key: '1', style: {}}]}>{() => null}</TransitionMotion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
  });

  it('should not throw on unmount', () => {
    spyOn(console, 'error');
    let kill = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          kill: false,
        };
      }
      componentWillMount() {
        kill = () => this.setState({kill: true});
      }
      render() {
        return this.state.kill
          ? null
          : <TransitionMotion
              defaultStyles={[{key: '1', style: {x: 0}}]}
              styles={[{key: '1', style: {x: spring(10)}}]}>
              {() => null}
            </TransitionMotion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
    mockRaf.step(2);
    kill();
    mockRaf.step(3);
    expect(console.error).not.toHaveBeenCalled();
  });

  it('should not throw on unmount with style function', () => {
    // similar as above test
    spyOn(console, 'error');
    let kill = () => {};
    class App extends React.Component {
      constructor() {
        super();
        this.state = {
          kill: false,
        };
      }
      componentWillMount() {
        kill = () => this.setState({kill: true});
      }
      render() {
        return this.state.kill
          ? null
          : <TransitionMotion
              defaultStyles={[{key: '1', style: {x: 0}}]}
              styles={() => [{key: '1', style: {x: spring(10)}}]}>
              {() => null}
            </TransitionMotion>;
      }
    }
    TestUtils.renderIntoDocument(<App />);
    mockRaf.step(2);
    kill();
    mockRaf.step(3);
    expect(console.error).not.toHaveBeenCalled();
  });

  it('should allow a defaultStyles', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[{key: '1', style: {a: 0}}]}
            styles={[{key: '1', style: {a: spring(10)}}]}>
            {([{style}]) => {
              count.push(style);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([{a: 0}]);
    mockRaf.step(4);
    expect(count).toEqual([
      {a: 0},
      {a: 0.4722222222222222},
      {a: 1.1897376543209877},
      {a: 2.0123698988340193},
      {a: 2.8557218143909084},
    ]);
  });

  it('should accept different spring configs', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[{key: '1', style: {a: 0}}]}
            styles={[
              {key: '1', style: {a: spring(10, {stiffness: 100, damping: 50, precision: 16})}},
            ]}>
            {([{style: {a}}]) => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    mockRaf.step(99);
    expect(count).toEqual([
      0,
      0.2777777777777778,
      0.5941358024691358,
      0.9081361454046639,
      1.213021309632678,
      1.5079182450697726,
      1.7929588941684615,
      2.0684390330691236,
      10,
    ]);
  });

  it('should interpolate many values', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[
              {key: '1', style: {a: 0, b: 10}},
              {key: '2', style: {c: 20}},
            ]}
            styles={[
              {key: '1', style: {a: spring(10), b: spring(410)}},
              {key: '2', style: {c: spring(420)}},
            ]}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[
      {key: '1', style: {a: 0, b: 10}, data: undefined},
      {key: '2', style: {c: 20}, data: undefined},
    ]]);
    mockRaf.step(4);
    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: undefined},
        {key: '2', style: {c: 20}, data: undefined},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: undefined},
        {key: '2', style: {c: 38.888888888888886}, data: undefined},
      ],
      [
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: undefined},
        {key: '2', style: {c: 67.589506172839506}, data: undefined},
      ],
      [
        {key: '1', style: {a: 2.0123698988340193, b: 90.49479595336075}, data: undefined},
        {key: '2', style: {c: 100.49479595336075}, data: undefined},
      ],
      [
        {key: '1', style: {a: 2.8557218143909084, b: 124.22887257563633}, data: undefined},
        {key: '2', style: {c: 134.22887257563632}, data: undefined},
      ],
    ]);
  });

  it('should invoke didLeave in last frame', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          val: [{key: '1', style: {x: spring(10)}}],
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            styles={this.state.val}
            willEnter={() => ({x: 0})}
            willLeave={() => ({x: spring(0)})}
            didLeave={(a) => { count.push(a); }}>
            {() => {
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([]);
    setState({
      val: [{key: '2', style: {x: 10}}],
    });
    mockRaf.step(999);
    expect(count).toEqual([
      {key: '1', data: undefined},
    ]);
  });

  it('should work with nested TransitionMotions', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[{key: 'owner', style: {x: 0}}]}
            styles={[{key: 'owner', style: {x: spring(10)}}]}>
            {([{style}]) => {
              count.push(style);
              return (
                <TransitionMotion
                  defaultStyles={[{key: 'child', style: {a: 10}}]}
                  styles={[{key: 'child', style: {a: spring(400)}}]}>
                  {([{style: s}]) => {
                    count.push(s);
                    return null;
                  }}
                </TransitionMotion>
              );
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([
      {x: 0},
      {a: 10},
    ]);
    mockRaf.step();
    expect(count).toEqual([
      {x: 0},
      {a: 10},
      {a: 28.416666666666668}, // child
      {x: 0.4722222222222222}, // owner
      {a: 28.416666666666668}, // child
    ]);
    mockRaf.step(2);
    expect(count).toEqual([
      {x: 0},
      {a: 10},
      {a: 28.416666666666668},
      {x: 0.4722222222222222},
      {a: 28.416666666666668},

      {a: 56.39976851851852}, // child
      {x: 1.1897376543209877}, // owner
      {a: 56.39976851851852}, // child

      {a: 88.48242605452674}, // child
      {x: 2.0123698988340193}, // owner
      {a: 88.48242605452674}, // child
    ]);
  });

  it('should reach destination value', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[{key: '1', style: {a: 0}}]}
            styles={[{key: '1', style: {a: spring(400)}}]}>
            {([{style: {a}}]) => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([0]);
    // Move "time" until we reach the final styles value
    mockRaf.step(111);
    expect(count.slice(0, 5)).toEqual([
      0,
      18.888888888888886,
      47.589506172839506,
      80.49479595336075,
      114.22887257563633,
    ]);
    expect(count[count.length - 1]).toEqual(400);
  });

  it('should support jumping to value', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          p: false,
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            styles={[{key: '1', style: {x: this.state.p ? 400 : spring(0)}}]}>
            {([{style}]) => {
              count.push(style);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([{x: 0}]);
    setState({p: true});
    expect(count).toEqual([
      {x: 0},
      {x: 0}, // this new 0 comes from owner update, causing TransitionMotion to re-render
    ]);
    mockRaf.step(10);
    // jumped to end, will only have two renders no matter how much we step
    expect(count).toEqual([
      {x: 0},
      {x: 0},
      {x: 400},
    ]);
    setState({p: false});
    mockRaf.step(3);
    expect(count).toEqual([
      {x: 0},
      {x: 0},
      {x: 400},
      {x: 400}, // redundant 0 comes from owner update again
      {x: 381.1111111111111},
      {x: 352.4104938271605},
      {x: 319.5052040466392},
    ]);
  });

  it('should behave well when many owner updates come in-between rAFs', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          val: [{key: '1', style: {x: spring(0)}}],
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            styles={this.state.val}
            willEnter={() => ({y: 0})}
            willLeave={() => ({y: spring(0)})}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[{key: '1', style: {x: 0}, data: undefined}]]);
    setState({
      val: [{key: '1', style: {x: 400}}, {key: '2', style: {y: 10}}],
    });
    setState({
      val: [{key: '1', style: {x: spring(100)}}],
    });
    mockRaf.step(2);
    setState({
      val: [{key: '1', style: {x: spring(400)}}],
    });
    mockRaf.step(2);
    expect(count).toEqual([
      [{key: '1', style: {x: 0}, data: undefined}],
      // this new 0 comes from owner update, causing TransitionMotion to
      // re-render
      [{key: '1', style: {x: 0}, data: undefined}],
      [
        {key: '1', style: {x: 400}, data: undefined},
        {key: '2', style: {y: 10}, data: undefined},
      ],
      [
        {key: '1', style: {x: 385.8333333333333}, data: undefined},
        {key: '2', style: {y: 9.527777777777779}, data: undefined},
      ],
      [
        {key: '1', style: {x: 364.3078703703703}, data: undefined},
        {key: '2', style: {y: 8.810262345679014}, data: undefined},
      ],
      [
        {key: '1', style: {x: 364.3078703703703}, data: undefined},
        {key: '2', style: {y: 8.810262345679014}, data: undefined},
      ],
      [
        {key: '1', style: {x: 353.79556970164606}, data: undefined},
        {key: '2', style: {y: 7.9876301011659825}, data: undefined},
      ],
      [
        {key: '1', style: {x: 350.02047519790233}, data: undefined},
        {key: '2', style: {y: 7.144278185609093}, data: undefined},
      ],
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(85);
    setState({a: spring(400)});
    // make sure we're still updating children even if there's nothing to interp
    expect(count.length).toBe(86);
  });

  it('should behave well when many owner styles function updates come in-between rAFs', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          val: [{key: '1', style: {x: spring(0)}}],
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            styles={() => this.state.val}
            willEnter={() => ({y: 0})}
            willLeave={() => ({y: spring(0)})}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }
    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[{key: '1', style: {x: 0}, data: undefined}]]);
    setState({
      val: [{key: '1', style: {x: 400}}, {key: '2', style: {y: 10}}],
    });
    setState({
      val: [{key: '1', style: {x: spring(100)}}],
    });
    mockRaf.step(2);
    setState({
      val: [{key: '1', style: {x: spring(400)}}],
    });
    mockRaf.step(2);
    expect(count).toEqual([
      [{key: '1', style: {x: 0}, data: undefined}],
      // this new 0 comes from owner update, causing TransitionMotion to
      // re-render
      [{key: '1', style: {x: 0}, data: undefined}],
      [
        {key: '1', style: {x: 400}, data: undefined},
        {key: '2', style: {y: 10}, data: undefined},
      ],
      [
        {key: '1', style: {x: 385.8333333333333}, data: undefined},
        {key: '2', style: {y: 9.527777777777779}, data: undefined},
      ],
      [
        {key: '1', style: {x: 364.3078703703703}, data: undefined},
        {key: '2', style: {y: 8.810262345679014}, data: undefined},
      ],
      [
        {key: '1', style: {x: 364.3078703703703}, data: undefined},
        {key: '2', style: {y: 8.810262345679014}, data: undefined},
      ],
      [
        {key: '1', style: {x: 353.79556970164606}, data: undefined},
        {key: '2', style: {y: 7.9876301011659825}, data: undefined},
      ],
      [
        {key: '1', style: {x: 350.02047519790233}, data: undefined},
        {key: '2', style: {y: 7.144278185609093}, data: undefined},
      ],
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(85);
    setState({a: spring(400)});
    // make sure we're still updating children even if there's nothing to interp
    expect(count.length).toBe(86);
  });

  it('should transition things in/out at the beginning', () => {
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            willLeave={() => ({c: spring(0)})}
            willEnter={() => ({d: 0})}
            defaultStyles={[{key: '1', style: {a: 0, b: 10}}, {key: '2', style: {c: 20}}]}
            styles={[
              {key: '1', style: {a: spring(10), b: spring(410)}},
              {key: '3', style: {d: spring(10)}},
            ]}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: undefined},
        {key: '2', style: {c: 20}, data: undefined},
        {key: '3', style: {d: 0}, data: undefined},
      ],
    ]);
    mockRaf.step(2);
    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: undefined},
        {key: '2', style: {c: 20}, data: undefined},
        {key: '3', style: {d: 0}, data: undefined},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: undefined},
        {key: '2', style: {c: 19.055555555555557}, data: undefined},
        {key: '3', style: {d: 0.4722222222222222}, data: undefined},
      ],
      [
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: undefined},
        {key: '2', style: {c: 17.62052469135803}, data: undefined},
        {key: '3', style: {d: 1.1897376543209877}, data: undefined},
      ],
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(91);
    expect(count[count.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: undefined},
      {key: '3', style: {d: 10}, data: undefined},
    ]);
  });

  it('should eliminate things in/out at the beginning', () => {
    // similar to previous test, but without willEnter/leave
    let count = [];
    class App extends React.Component {
      render() {
        return (
          <TransitionMotion
            defaultStyles={[{key: '1', style: {a: 0, b: 10}}, {key: '2', style: {c: 20}}]}
            styles={[
              {key: '1', style: {a: spring(10), b: spring(410)}},
              {key: '3', style: {d: spring(10)}},
            ]}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    expect(count).toEqual([[
      {key: '1', style: {a: 0, b: 10}, data: undefined},
      {key: '3', style: {d: 10}, data: undefined},
    ]]);
    mockRaf.step(2);
    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: undefined},
        {key: '3', style: {d: 10}, data: undefined},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: undefined},
        {key: '3', style: {d: 10}, data: undefined},
      ],
      [
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: undefined},
        {key: '3', style: {d: 10}, data: undefined},
      ],
    ]);
  });

  it('should carry around the ignored values', () => {
    let count = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          val: [
            {key: '1', style: {a: spring(10), b: spring(410)}, data: [3]},
            {key: '3', style: {d: spring(10)}, data: [4]},
          ],
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            willLeave={() => ({c: spring(0)})}
            willEnter={() => ({d: 0})}
            defaultStyles={[
              {key: '1', style: {a: 0, b: 10}, data: [1]},
              {key: '2', style: {c: 20}, data: [2]},
            ]}
            styles={this.state.val}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    // somewhat defined behavior: notice that data is 3, not 1. For simplicity
    // of current implementation we've decided not to render data: [1] from
    // defaultStyles (this is a problem unique to TransitionMotion, since no
    // other component carries unrelated data)
    expect(count).toEqual([[
      {key: '1', style: {a: 0, b: 10}, data: [3]},
      {key: '2', style: {c: 20}, data: [2]},
      {key: '3', style: {d: 0}, data: [4]},
    ]]);
    mockRaf.step(2);
    setState({
      val: [
        {key: '1', style: {a: spring(10), b: spring(410)}, data: [5]},
        {key: '3', style: {d: spring(10)}, data: [6]},
      ],
    });
    mockRaf.step(1);
    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: [3]},
        {key: '2', style: {c: 20}, data: [2]},
        {key: '3', style: {d: 0}, data: [4]},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: [3]},
        {key: '2', style: {c: 19.055555555555557}, data: [2]},
        {key: '3', style: {d: 0.4722222222222222}, data: [4]},
      ],
      [
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: [3]},
        {key: '2', style: {c: 17.62052469135803}, data: [2]},
        {key: '3', style: {d: 1.1897376543209877}, data: [4]},
      ],
      // notice the `data` change!
      [
        // from the setState
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: [5]},
        {key: '2', style: {c: 17.62052469135803}, data: [2]},
        {key: '3', style: {d: 1.1897376543209877}, data: [6]},
      ],
      [
        {key: '1', style: {a: 2.0123698988340193, b: 90.49479595336075}, data: [5]},
        {key: '2', style: {c: 15.975260202331965}, data: [2]},
        {key: '3', style: {d: 2.0123698988340193}, data: [6]},
      ],
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(92);
    expect(count[count.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: [5]},
      {key: '3', style: {d: 10}, data: [6]},
    ]);
    setState({
      val: [
        // `data` changes again
        {key: '1', style: {a: spring(10), b: spring(410)}, data: [7]},
        {key: '3', style: {d: spring(10)}, data: [8]},
      ],
    });
    mockRaf.step(10); // no effect, stopped
    expect(count.length).toBe(93); // rendered once from setState
    expect(count[count.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: [7]},
      {key: '3', style: {d: 10}, data: [8]},
    ]);
  });

  it('should carry around the ignored values in styles function', () => {
    let count = [];
    let prevValues = [];
    let setState = () => {};
    class App extends React.Component {
      constructor() {
        super();

        this.state = {
          val: [
            {key: '1', style: {a: spring(10), b: spring(410)}, data: [3]},
            {key: '3', style: {d: spring(10)}, data: [4]},
          ],
        };
      }
      componentWillMount() {
        setState = this.setState.bind(this);
      }
      render() {
        return (
          <TransitionMotion
            willLeave={() => ({c: spring(0)})}
            willEnter={() => ({d: 0})}
            defaultStyles={[
              {key: '1', style: {a: 0, b: 10}, data: [1]},
              {key: '2', style: {c: 20}, data: [2]},
            ]}
            styles={a => {
              prevValues.push(a);
              return this.state.val;
            }}>
            {a => {
              count.push(a);
              return null;
            }}
          </TransitionMotion>
        );
      }
    }

    TestUtils.renderIntoDocument(<App />);

    // somewhat defined behavior: notice that data is 3, not 1. For simplicity
    // of current implementation we've decided not to render data: [1] from
    // defaultStyles (this is a problem unique to TransitionMotion, since no
    // other component carries unrelated data)
    expect(count).toEqual([[
      {key: '1', style: {a: 0, b: 10}, data: [3]},
      {key: '2', style: {c: 20}, data: [2]},
      {key: '3', style: {d: 0}, data: [4]},
    ]]);
    mockRaf.step(2);
    setState({
      val: [
        {key: '1', style: {a: spring(10), b: spring(410)}, data: [5]},
        {key: '3', style: {d: spring(10)}, data: [6]},
      ],
    });
    mockRaf.step(1);
    expect(count).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: [3]},
        {key: '2', style: {c: 20}, data: [2]},
        {key: '3', style: {d: 0}, data: [4]},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: [3]},
        {key: '2', style: {c: 19.055555555555557}, data: [2]},
        {key: '3', style: {d: 0.4722222222222222}, data: [4]},
      ],
      [
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: [3]},
        {key: '2', style: {c: 17.62052469135803}, data: [2]},
        {key: '3', style: {d: 1.1897376543209877}, data: [4]},
      ],
      // notice the data change!
      [
        // from the setState
        {key: '1', style: {a: 1.1897376543209877, b: 57.589506172839506}, data: [5]},
        {key: '2', style: {c: 17.62052469135803}, data: [2]},
        {key: '3', style: {d: 1.1897376543209877}, data: [6]},
      ],
      [
        {key: '1', style: {a: 2.0123698988340193, b: 90.49479595336075}, data: [5]},
        {key: '2', style: {c: 15.975260202331965}, data: [2]},
        {key: '3', style: {d: 2.0123698988340193}, data: [6]},
      ],
    ]);
    mockRaf.step(999);
    expect(count.length).toBe(92);
    expect(count[count.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: [5]},
      {key: '3', style: {d: 10}, data: [6]},
    ]);
    setState({
      val: [
        // `data` changes again
        {key: '1', style: {a: spring(10), b: spring(410)}, data: [7]},
        {key: '3', style: {d: spring(10)}, data: [8]},
      ],
    });
    mockRaf.step(10); // no effect, stopped
    expect(count.length).toBe(93); // rendered once from setState
    expect(count[count.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: [7]},
      {key: '3', style: {d: 10}, data: [8]},
    ]);

    expect(prevValues.slice(0, 3)).toEqual([
      [
        {key: '1', style: {a: 0, b: 10}, data: [1]},
        {key: '2', style: {c: 20}, data: [2]},
      ],
      [
        {key: '1', style: {a: 0, b: 10}, data: [3]},
        {key: '2', style: {c: 20}, data: [2]},
        {key: '3', style: {d: 0}, data: [4]},
      ],
      [
        {key: '1', style: {a: 0.4722222222222222, b: 28.888888888888886}, data: [3]},
        {key: '2', style: {c: 19.055555555555557}, data: [2]},
        {key: '3', style: {d: 0.4722222222222222}, data: [4]},
      ],
    ]);
    expect(prevValues[prevValues.length - 1]).toEqual([
      {key: '1', style: {a: 10, b: 410}, data: [7]},
      {key: '3', style: {d: 10}, data: [8]},
    ]);
  });
});


================================================
FILE: test/createMockRaf.js
================================================
/* @flow */

type Callback = (now: number) => void;

export default function (): Object {
  let allCallbacks = [];
  let prevTime = 0;
  let id = 0;

  const now = () => prevTime;

  const raf = (cb: Callback) => {
    id++;
    allCallbacks.push({id, cb});
    return id;
  };

  raf.cancel = id2 => {
    allCallbacks = allCallbacks.filter(item => item.id !== id2);
  };

  const defaultTimeInterval = 1000 / 60;
  const singleStep = ms => {
    const allCallbacksBefore = allCallbacks;
    allCallbacks = [];

    prevTime += ms;
    allCallbacksBefore.forEach(({cb}) => cb(prevTime));
  };

  const step = (howMany = 1, ms = defaultTimeInterval) => {
    for (let i = 0; i < howMany; i++) {
      singleStep(ms);
    }
  };

  return {now, raf, step};
}


================================================
FILE: test/index.js
================================================
const testsContext = require.context('./', true, /-test\.js$/);

testsContext.keys().forEach(testsContext);


================================================
FILE: test/integration/README.md
================================================
Simple folder for testing whether the release worked or not.

Please run this:
```
rm -rf bower_components
rm -rf node_modules
bower install
npm install
node -e 'console.log(require("react-motion"))'
```

Check that the output of that looks normal.

For Bower, please also open up bower.html


================================================
FILE: test/integration/bower.html
================================================
<html>
  <head></head>
  <body>
    <script src="bower_components/react/react.js"></script>
    <script src="bower_components/react-motion/build/react-motion.js"></script>
    <script>
      if (ReactMotion.spring && ReactMotion.presets && ReactMotion.TransitionMotion) {
        document.write('Everything looks fine. Check the console too.');
      } else {
        document.write('Something broke. Please check the console.');
      }
      console.log(ReactMotion);
    </script>
  </body>
</html>


================================================
FILE: test/integration/bower.json
================================================
{
  "name": "integration",
  "version": "0.4.1",
  "homepage": "https://github.com/chenglou/react-motion",
  "authors": [
    "Cheng Lou <chenglou92@gmail.com>"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "react-motion": "https://unpkg.com/react-motion/bower.zip"
  }
}


================================================
FILE: test/integration/package.json
================================================
{
  "name": "integration",
  "private": true,
  "version": "1.0.0",
  "description": "Simple folder for testing whether the release worked or not.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react-motion": "^0.5.1"
  }
}


================================================
FILE: test/mergeDiff-test.js
================================================
import mergeDiff from '../src/mergeDiff';

const id = (_, s) => s;
const n = () => null;

// helper to make the tests more concise
function test(prevRaw, nextRaw, expectedRaw, customOnRemove) {
  // we elaborately construct prev/nextKeyStyleValMap + randomized style value to
  // check that the style object of the latter correctly merged into the final
  // output
  let prev = [];
  let prevKeyStyleValMap = {};
  prevRaw.forEach(num => {
    const styleVal = Math.random();
    // key needs to be a string; cast it
    prev.push({key: String(num), style: {a: styleVal}});
    prevKeyStyleValMap[num] = styleVal;
  });
  let next = [];
  let nextKeyStyleValMap = {};
  nextRaw.forEach(num => {
    const styleVal = Math.random();
    next.push({key: String(num), style: {a: styleVal}});
    nextKeyStyleValMap[num] = styleVal;
  });

  const expected = expectedRaw.map(num => {
    return {
      key: String(num),
      style: {a: Object.prototype.hasOwnProperty.call(nextKeyStyleValMap, num) ? nextKeyStyleValMap[num] : prevKeyStyleValMap[num]},
    };
  });

  expect(mergeDiff(prev, next, n)).toEqual(next);
  // some tests pass in a `customOnRemove` to check edge cases; interpret
  // `expected`/`expectedRaw` as the output of mergeDiff using `customOnRemove`
  // instead of the default `id` function
  expect(mergeDiff(prev, next, customOnRemove || id)).toEqual(expected);
}

describe('mergeDiff', () => {
  it('should work with various merge orders', () => {
    // most of these tests are significant. Don't casually remove some. Those
    // marked as "meh" are the ones whose order can differ. We've chosen a
    // deterministic default in our mergeDiff implementation
    test([4], [], [4]);
    test([], [3], [3]);
    test([3], [3], [3]);
    test([], [], []);
    test([2, 4, 5, 6], [2, 3, 4, 5], [2, 3, 4, 5, 6]);
    test([2, 4, 5, 6, 7], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6, 7]);
    test([1, 2, 3], [2, 3, 4], [1, 2, 3, 4]);
    test([2, 3, 4], [1, 2, 3], [1, 2, 3, 4]);
    test([4], [1, 2, 3], [4, 1, 2, 3]); // meh
    test([1, 2, 3], [4], [1, 2, 3, 4]); // meh
    test([4, 2], [1, 2, 3], [4, 1, 2, 3]); // meh
    test([2, 4], [1, 2, 3], [1, 2, 4, 3]); // meh
    test([1, 5, 10], [3, 5, 7, 10], [1, 3, 5, 7, 10]); // meh
    test([4, 5, 10], [3, 5, 7, 10], [4, 3, 5, 7, 10]); // meh
    test([4], [3], [4, 3]); // meh
    test([1, 5], [5, 3], [1, 5, 3]);
    test([5, 6], [3, 5], [3, 5, 6]);
    test([1, 2, 3], [3, 2, 1], [3, 2, 1]);
    test([3, 2, 1], [1, 2, 3], [1, 2, 3]);
    test([1, 2, 3], [2, 1, 3], [2, 1, 3]);
    test([1, 2, 3], [1, 3, 2], [1, 3, 2]);
    test([1, 2, 3], [1, 2, 3], [1, 2, 3]);
  });

  it('should work with some more typical onRemove callbacks', () => {
    test([1, 2, 3], [1, 9], [1, 2, 9], (index, s) => index === 1 ? s : null);
    test([1, 2, 3, 4], [5, 4, 2], [1, 5, 4, 2], (index, s) => index === 0 ? s : null);
  });

  it('should not call cb more than once per disappearing key', () => {
    let count = 0;
    test([1], [], [], () => {
      count++;
      return null;
    });
    expect(count).toBe(1);
  });
});


================================================
FILE: test/stripStyle-test.js
================================================
import stripStyle from '../src/stripStyle';
import spring from '../src/spring';

describe('stripStyle', () => {
  it('should return spring object into value', () => {
    expect(stripStyle({a: spring(1, [1, 2])})).toEqual({a: 1});
  });

  it('should ignore non-configured values', () => {
    expect(stripStyle({a: 10, b: 0})).toEqual({a: 10, b: 0});
  });
});


================================================
FILE: webpack.config.js
================================================
'use strict';

module.exports = {
  mode: "development",
  devtool:
    process.env.NODE_ENV === 'development' ? 'eval-source-map' : 'source-map',
  entry: {
    'demo0-simple-transition': './demos/demo0-simple-transition/index.jsx',
    'demo1-chat-heads': './demos/demo1-chat-heads/index.jsx',
    'demo2-draggable-balls': './demos/demo2-draggable-balls/index.jsx',
    'demo3-todomvc-list-transition': './demos/demo3-todomvc-list-transition/index.jsx',
    'demo4-photo-gallery': './demos/demo4-photo-gallery/index.jsx',
    'demo5-spring-parameters-chooser': './demos/demo5-spring-parameters-chooser/index.jsx',
    'demo7-water-ripples': './demos/demo7-water-ripples/index.jsx',
    'demo8-draggable-list': './demos/demo8-draggable-list/index.jsx',
  },
  output: {
    filename: '[name]/all.js',
    publicPath: '/demos/',
    path: __dirname + '/demos/',
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /build|lib|bower_components|node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.jsx?$/,
        loader: 'eslint-loader',
        exclude: /build|lib|bower_components|node_modules/
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx']
  },
};
Download .txt
gitextract_zo4f_ak9/

├── .babelrc
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .npmignore
├── .size-snapshot.json
├── .travis.yml
├── AUTHORS
├── HISTORY.md
├── LICENSE
├── README.md
├── bower.json
├── demos/
│   ├── README.md
│   ├── demo0-simple-transition/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo1-chat-heads/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo2-draggable-balls/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo3-todomvc-list-transition/
│   │   ├── Demo.jsx
│   │   ├── index.css
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo4-photo-gallery/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo5-spring-parameters-chooser/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   ├── demo7-water-ripples/
│   │   ├── Demo.jsx
│   │   ├── index.html
│   │   └── index.jsx
│   └── demo8-draggable-list/
│       ├── Demo.jsx
│       ├── index.html
│       └── index.jsx
├── karma.conf.js
├── package.json
├── rollup.config.js
├── server.js
├── src/
│   ├── Motion.js
│   ├── StaggeredMotion.js
│   ├── TransitionMotion.js
│   ├── Types.js
│   ├── mapToZero.js
│   ├── mergeDiff.js
│   ├── presets.js
│   ├── react-motion.js
│   ├── reorderKeys.js
│   ├── shouldStopAnimation.js
│   ├── spring.js
│   ├── stepper.js
│   └── stripStyle.js
├── test/
│   ├── Motion-test.js
│   ├── StaggeredMotion-test.js
│   ├── TransitionMotion-test.js
│   ├── createMockRaf.js
│   ├── index.js
│   ├── integration/
│   │   ├── README.md
│   │   ├── bower.html
│   │   ├── bower.json
│   │   └── package.json
│   ├── mergeDiff-test.js
│   └── stripStyle-test.js
└── webpack.config.js
Download .txt
SYMBOL INDEX (162 symbols across 21 files)

FILE: demos/demo0-simple-transition/Demo.jsx
  class Demo (line 4) | class Demo extends React.Component {
    method constructor (line 5) | constructor(props) {
    method render (line 19) | render() {

FILE: demos/demo1-chat-heads/Demo.jsx
  class Demo (line 5) | class Demo extends React.Component {
    method constructor (line 6) | constructor(props) {
    method componentDidMount (line 11) | componentDidMount() {
    method render (line 37) | render() {

FILE: demos/demo2-draggable-balls/Demo.jsx
  function reinsert (line 7) | function reinsert(arr, from, to) {
  function clamp (line 15) | function clamp(n, min, max) {
  class Demo (line 31) | class Demo extends React.Component {
    method constructor (line 32) | constructor(props) {
    method componentDidMount (line 43) | componentDidMount() {
    method render (line 84) | render() {

FILE: demos/demo3-todomvc-list-transition/Demo.jsx
  class Demo (line 4) | class Demo extends React.Component {
    method constructor (line 5) | constructor(props) {
    method willEnter (line 98) | willEnter() {
    method willLeave (line 105) | willLeave() {
    method render (line 112) | render() {

FILE: demos/demo4-photo-gallery/Demo.jsx
  constant NEXT (line 5) | const NEXT = 'show-next';
  class Demo (line 7) | class Demo extends React.Component {
    method constructor (line 8) | constructor(props) {
    method render (line 31) | render() {

FILE: demos/demo5-spring-parameters-chooser/Demo.jsx
  class Demo (line 9) | class Demo extends React.Component {
    method constructor (line 10) | constructor(props) {
    method componentDidMount (line 22) | componentDidMount() {
    method render (line 83) | render() {

FILE: demos/demo7-water-ripples/Demo.jsx
  class Demo (line 6) | class Demo extends React.Component {
    method constructor (line 7) | constructor(props) {
    method render (line 35) | render() {

FILE: demos/demo8-draggable-list/Demo.jsx
  function reinsert (line 5) | function reinsert(arr, from, to) {
  function clamp (line 13) | function clamp(n, min, max) {
  class Demo (line 20) | class Demo extends React.Component {
    method constructor (line 21) | constructor(props) {
    method componentDidMount (line 32) | componentDidMount() {
    method render (line 77) | render() {

FILE: src/Motion.js
  method if (line 113) | if (this.unmounting || this.animationID != null) {

FILE: src/StaggeredMotion.js
  method for (line 33) | for (let i = 0; i < currentStyles.length; i++) {
  method if (line 102) | if (!Object.prototype.hasOwnProperty.call(unreadPropStyle, key)) {
  method if (line 108) | if (!dirty) {
  method if (line 135) | if (this.unmounting || this.animationID != null) {

FILE: src/TransitionMotion.js
  function rehydrateStyles (line 33) | function rehydrateStyles(
  method if (line 72) | if (mergedPropsStyles.length !== destStyles.length) {
  method if (line 77) | if (mergedPropsStyles[i].key !== destStyles[i].key) {
  method if (line 86) | if (
  method if (line 173) | if (oldMergedPropsStyles[j].key === newMergedPropsStyleCell.key) {

FILE: src/mapToZero.js
  method if (line 8) | if (Object.prototype.hasOwnProperty.call(obj, key)) {

FILE: src/mergeDiff.js
  method if (line 48) | if (!Object.prototype.hasOwnProperty.call(nextKeyIndex, prev[i].key)) {

FILE: src/reorderKeys.js
  function reorderKeys (line 4) | function reorderKeys() {

FILE: src/shouldStopAnimation.js
  function shouldStopAnimation (line 6) | function shouldStopAnimation(

FILE: src/stepper.js
  function stepper (line 8) | function stepper(

FILE: src/stripStyle.js
  function stripStyle (line 7) | function stripStyle(style: Style): PlainStyle {

FILE: test/Motion-test.js
  class App (line 27) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 55) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 82) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 143) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 155) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 181) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 208) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 240) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 270) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 320) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 350) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 404) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 437) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 475) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {
  class App (line 510) | class App extends React.Component {
    method render (line 28) | render() {
    method render (line 56) | render() {
    method render (line 83) | render() {
    method render (line 144) | render() {
    method constructor (line 156) | constructor() {
    method componentWillMount (line 163) | componentWillMount() {
    method render (line 166) | render() {
    method render (line 182) | render() {
    method render (line 209) | render() {
    method render (line 241) | render() {
    method render (line 271) | render() {
    method render (line 321) | render() {
    method constructor (line 351) | constructor() {
    method componentWillMount (line 358) | componentWillMount() {
    method render (line 361) | render() {
    method render (line 405) | render() {
    method render (line 438) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method constructor (line 511) | constructor() {
    method componentWillMount (line 518) | componentWillMount() {
    method render (line 521) | render() {

FILE: test/StaggeredMotion-test.js
  class App (line 22) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 38) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 66) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 95) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 127) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 161) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 213) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 249) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {
  class App (line 302) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 39) | constructor() {
    method componentWillMount (line 46) | componentWillMount() {
    method render (line 49) | render() {
    method render (line 67) | render() {
    method render (line 96) | render() {
    method render (line 128) | render() {
    method render (line 162) | render() {
    method render (line 214) | render() {
    method constructor (line 250) | constructor() {
    method componentWillMount (line 257) | componentWillMount() {
    method render (line 260) | render() {
    method constructor (line 303) | constructor() {
    method componentWillMount (line 310) | componentWillMount() {
    method render (line 313) | render() {

FILE: test/TransitionMotion-test.js
  class App (line 22) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 34) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 66) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 95) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 125) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 159) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 214) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 253) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 310) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 342) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 396) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 475) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 553) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 611) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 655) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {
  class App (line 761) | class App extends React.Component {
    method render (line 23) | render() {
    method constructor (line 35) | constructor() {
    method componentWillMount (line 42) | componentWillMount() {
    method render (line 45) | render() {
    method constructor (line 67) | constructor() {
    method componentWillMount (line 73) | componentWillMount() {
    method render (line 76) | render() {
    method render (line 96) | render() {
    method render (line 126) | render() {
    method render (line 160) | render() {
    method constructor (line 215) | constructor() {
    method componentWillMount (line 222) | componentWillMount() {
    method render (line 225) | render() {
    method render (line 254) | render() {
    method render (line 311) | render() {
    method constructor (line 343) | constructor() {
    method componentWillMount (line 350) | componentWillMount() {
    method render (line 353) | render() {
    method constructor (line 397) | constructor() {
    method componentWillMount (line 404) | componentWillMount() {
    method render (line 407) | render() {
    method constructor (line 476) | constructor() {
    method componentWillMount (line 483) | componentWillMount() {
    method render (line 486) | render() {
    method render (line 554) | render() {
    method render (line 612) | render() {
    method constructor (line 656) | constructor() {
    method componentWillMount (line 666) | componentWillMount() {
    method render (line 669) | render() {
    method constructor (line 762) | constructor() {
    method componentWillMount (line 772) | componentWillMount() {
    method render (line 775) | render() {

FILE: test/mergeDiff-test.js
  function test (line 7) | function test(prevRaw, nextRaw, expectedRaw, customOnRemove) {
Condensed preview — 68 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (199K chars).
[
  {
    "path": ".babelrc",
    "chars": 380,
    "preview": "{\n  \"presets\": [\n    [\"@babel/env\", { \"modules\": \"commonjs\", \"loose\": true }],\n    \"@babel/flow\",\n    \"@babel/react\"\n  ]"
  },
  {
    "path": ".eslintignore",
    "chars": 133,
    "preview": "build\ncoverage\nlib\nnode_modules\n**/*/all.js\nwebpack.*.js\nserver.js\nkarma.*.js\ntest/integration\ndemos/demo6/babel.js\ndemo"
  },
  {
    "path": ".eslintrc",
    "chars": 2419,
    "preview": "{\n  \"parser\": \"babel-eslint\",\n  \"extends\": [\"airbnb\", \"prettier\"],\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    "
  },
  {
    "path": ".flowconfig",
    "chars": 708,
    "preview": "[ignore]\n.*/node_modules/fbjs/lib/PromiseMap.js\n.*/node_modules/fbjs/lib/fetchWithRetries.js\n.*/node_modules/fbjs/lib/De"
  },
  {
    "path": ".gitignore",
    "chars": 112,
    "preview": "logs\n*.log\n\npids\n*.pid\n*.seed\n\ncoverage\nnode_modules\nbower_components\n\n.DS_Store\n\n/demos/**/all.*\n/build/\n/lib/\n"
  },
  {
    "path": ".npmignore",
    "chars": 159,
    "preview": "/.*\n\n/bower_components/\n\n/coverage/\n/demos/\n/test/\n\n/karma.conf.js\n/webpack.*\n/server.js\n\n# sublime\n/*.sublime-project\n/"
  },
  {
    "path": ".size-snapshot.json",
    "chars": 463,
    "preview": "{\n  \"build/react-motion.js\": {\n    \"bundled\": 77059,\n    \"minified\": 22596,\n    \"gzipped\": 6616\n  },\n  \"build/react-moti"
  },
  {
    "path": ".travis.yml",
    "chars": 114,
    "preview": "language: node_js\n\nnode_js:\n  - 10\n\nscript:\n - npm run -s lint\n - npm run -s flow_check\n - npm run -s test:travis\n"
  },
  {
    "path": "AUTHORS",
    "chars": 598,
    "preview": "Adrian le Bas\nAmadeus Junqueira\nBenjamin San Souci\nBishop Zareh\nBrenton Simpson\nCesar Andreu\nCheng Lou\nDan Abramov\nDanie"
  },
  {
    "path": "HISTORY.md",
    "chars": 7800,
    "preview": "Legend:\n- [B]: Breaking\n- [F]: Fix\n- [I]: Improvement\n\n### 0.5.1 (August 28th 2017)\n- [F] New flow definitions, fixes ch"
  },
  {
    "path": "LICENSE",
    "chars": 1088,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 React Motion authors\n\nPermission is hereby granted, free of charge, to any per"
  },
  {
    "path": "README.md",
    "chars": 15421,
    "preview": "# React-Motion\n\n[![Build Status](https://travis-ci.org/chenglou/react-motion.svg?branch=master)](https://travis-ci.org/c"
  },
  {
    "path": "bower.json",
    "chars": 746,
    "preview": "{\n  \"name\": \"react-motion\",\n  \"version\": \"0.5.1\",\n  \"homepage\": \"https://github.com/chenglou/react-motion\",\n  \"authors\":"
  },
  {
    "path": "demos/README.md",
    "chars": 253,
    "preview": "## Demos folder\n\n**Note**: since this is the master branch, the demos might be a bit ahead of the current stable API. [T"
  },
  {
    "path": "demos/demo0-simple-transition/Demo.jsx",
    "chars": 1052,
    "preview": "import React from 'react';\nimport {Motion, spring} from '../../src/react-motion';\n\nexport default class Demo extends Rea"
  },
  {
    "path": "demos/demo0-simple-transition/index.html",
    "chars": 604,
    "preview": "<!doctype html>\n<html lang=\"en\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\""
  },
  {
    "path": "demos/demo0-simple-transition/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo1-chat-heads/Demo.jsx",
    "chars": 1597,
    "preview": "import React from 'react';\nimport {StaggeredMotion, spring, presets} from '../../src/react-motion';\nimport range from 'l"
  },
  {
    "path": "demos/demo1-chat-heads/index.html",
    "chars": 919,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Chat Heads</title>\n  <meta name=\"viewport\" co"
  },
  {
    "path": "demos/demo1-chat-heads/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo2-draggable-balls/Demo.jsx",
    "chars": 4384,
    "preview": "import React from 'react';\nimport {Motion, spring} from '../../src/react-motion';\nimport range from 'lodash.range';\n\ncon"
  },
  {
    "path": "demos/demo2-draggable-balls/index.html",
    "chars": 914,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Grid of Balls</title>\n  <meta name=\"viewport\""
  },
  {
    "path": "demos/demo2-draggable-balls/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo3-todomvc-list-transition/Demo.jsx",
    "chars": 6183,
    "preview": "import React from 'react';\nimport {TransitionMotion, spring, presets} from '../../src/react-motion';\n\nexport default cla"
  },
  {
    "path": "demos/demo3-todomvc-list-transition/index.css",
    "chars": 8661,
    "preview": "hr {\n  margin: 20px 0;\n  border: 0;\n  border-top: 1px dashed #c5c5c5;\n  border-bottom: 1px dashed #f7f7f7;\n}\n\n.learn a {"
  },
  {
    "path": "demos/demo3-todomvc-list-transition/index.html",
    "chars": 233,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>RedoMVC</title>\n  <link rel=\"stylesheet\" href"
  },
  {
    "path": "demos/demo3-todomvc-list-transition/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo4-photo-gallery/Demo.jsx",
    "chars": 2375,
    "preview": "import React from 'react';\nimport {Motion, spring} from '../../src/react-motion';\n\nconst springSettings = {stiffness: 17"
  },
  {
    "path": "demos/demo4-photo-gallery/index.html",
    "chars": 593,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>How Many Demos Do You Need</title>\n  <meta na"
  },
  {
    "path": "demos/demo4-photo-gallery/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo5-spring-parameters-chooser/Demo.jsx",
    "chars": 5318,
    "preview": "import React from 'react';\nimport {Motion, spring} from '../../src/react-motion';\nimport range from 'lodash.range';\n\ncon"
  },
  {
    "path": "demos/demo5-spring-parameters-chooser/index.html",
    "chars": 2524,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Choose your weapon</title>\n  <meta name=\"view"
  },
  {
    "path": "demos/demo5-spring-parameters-chooser/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo7-water-ripples/Demo.jsx",
    "chars": 1821,
    "preview": "import React from 'react';\nimport {TransitionMotion, spring} from '../../src/react-motion';\n\nconst leavingSpringConfig ="
  },
  {
    "path": "demos/demo7-water-ripples/index.html",
    "chars": 647,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Ripples</title>\n  <meta name=\"viewport\" conte"
  },
  {
    "path": "demos/demo7-water-ripples/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "demos/demo8-draggable-list/Demo.jsx",
    "chars": 3389,
    "preview": "import React from 'react';\nimport {Motion, spring} from '../../src/react-motion';\nimport range from 'lodash.range';\n\nfun"
  },
  {
    "path": "demos/demo8-draggable-list/index.html",
    "chars": 1599,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Framer cards</title>\n  <meta name=\"viewport\" "
  },
  {
    "path": "demos/demo8-draggable-list/index.jsx",
    "chars": 152,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport Demo from './Demo';\n\nReactDOM.render(<Demo />, docum"
  },
  {
    "path": "karma.conf.js",
    "chars": 1837,
    "preview": "'use strict';\n\nvar path = require('path');\n\nvar withCoverage = process.argv.indexOf('coverage') !== -1 || process.env.CO"
  },
  {
    "path": "package.json",
    "chars": 3888,
    "preview": "{\n  \"name\": \"react-motion\",\n  \"version\": \"0.5.2\",\n  \"description\": \"A spring that solves your animation problems.\",\n  \"m"
  },
  {
    "path": "rollup.config.js",
    "chars": 1943,
    "preview": "import nodeResolve from 'rollup-plugin-node-resolve';\nimport commonjs from 'rollup-plugin-commonjs';\nimport babel from '"
  },
  {
    "path": "server.js",
    "chars": 508,
    "preview": "'use strict';\n\nprocess.env.NODE_ENV = 'development';\n\nvar webpack = require('webpack');\nvar WebpackDevServer = require('"
  },
  {
    "path": "src/Motion.js",
    "chars": 8414,
    "preview": "/* @flow */\nimport mapToZero from './mapToZero';\nimport stripStyle from './stripStyle';\nimport stepper from './stepper';"
  },
  {
    "path": "src/StaggeredMotion.js",
    "chars": 9651,
    "preview": "/* @flow */\nimport mapToZero from './mapToZero';\nimport stripStyle from './stripStyle';\nimport stepper from './stepper';"
  },
  {
    "path": "src/TransitionMotion.js",
    "chars": 20131,
    "preview": "/* @flow */\nimport mapToZero from './mapToZero';\nimport stripStyle from './stripStyle';\nimport stepper from './stepper';"
  },
  {
    "path": "src/Types.js",
    "chars": 2592,
    "preview": "/* @flow */\n\n// Babel 5.x doesn't support type parameters, so we make this alias here out of\n// Babel's sight.\n/* eslint"
  },
  {
    "path": "src/mapToZero.js",
    "chars": 344,
    "preview": "/* @flow */\nimport type { PlainStyle, Style } from './Types';\n\n// currently used to initiate the velocity style object t"
  },
  {
    "path": "src/mergeDiff.js",
    "chars": 4273,
    "preview": "/* @flow */\nimport type { TransitionStyle } from './Types';\n\n// core keys merging algorithm. If previous render's keys a"
  },
  {
    "path": "src/presets.js",
    "chars": 241,
    "preview": "/* @flow */\nexport default {\n  noWobble: { stiffness: 170, damping: 26 }, // the default, if nothing provided\n  gentle: "
  },
  {
    "path": "src/react-motion.js",
    "chars": 431,
    "preview": "/* @flow */\nexport { default as Motion } from './Motion';\nexport { default as StaggeredMotion } from './StaggeredMotion'"
  },
  {
    "path": "src/reorderKeys.js",
    "chars": 329,
    "preview": "/* @flow */\n\nlet hasWarned = false;\nexport default function reorderKeys() {\n  if (process.env.NODE_ENV === 'development'"
  },
  {
    "path": "src/shouldStopAnimation.js",
    "chars": 832,
    "preview": "/* @flow */\nimport type { PlainStyle, Style, Velocity } from './Types';\n\n// usage assumption: currentStyle values have a"
  },
  {
    "path": "src/spring.js",
    "chars": 326,
    "preview": "/* @flow */\nimport presets from './presets';\nimport type { OpaqueConfig, SpringHelperConfig } from './Types';\n\nconst def"
  },
  {
    "path": "src/stepper.js",
    "chars": 1288,
    "preview": "/* @flow */\n\n// stepper is used a lot. Saves allocation to return the same array wrapper.\n// This is fine and danger-fre"
  },
  {
    "path": "src/stripStyle.js",
    "chars": 491,
    "preview": "/* @flow */\n// turn {x: {val: 1, stiffness: 1, damping: 2}, y: 2} generated by\n// `{x: spring(1, {stiffness: 1, damping:"
  },
  {
    "path": "test/Motion-test.js",
    "chars": 13052,
    "preview": "/* eslint-disable class-methods-use-this */\nimport React from 'react';\nimport {spring} from '../src/react-motion';\nimpor"
  },
  {
    "path": "test/StaggeredMotion-test.js",
    "chars": 9407,
    "preview": "/* eslint-disable class-methods-use-this */\nimport React from 'react';\nimport {spring} from '../src/react-motion';\nimpor"
  },
  {
    "path": "test/TransitionMotion-test.js",
    "chars": 26424,
    "preview": "/* eslint-disable class-methods-use-this */\nimport React from 'react';\nimport {spring} from '../src/react-motion';\nimpor"
  },
  {
    "path": "test/createMockRaf.js",
    "chars": 758,
    "preview": "/* @flow */\n\ntype Callback = (now: number) => void;\n\nexport default function (): Object {\n  let allCallbacks = [];\n  let"
  },
  {
    "path": "test/index.js",
    "chars": 108,
    "preview": "const testsContext = require.context('./', true, /-test\\.js$/);\n\ntestsContext.keys().forEach(testsContext);\n"
  },
  {
    "path": "test/integration/README.md",
    "chars": 292,
    "preview": "Simple folder for testing whether the release worked or not.\n\nPlease run this:\n```\nrm -rf bower_components\nrm -rf node_m"
  },
  {
    "path": "test/integration/bower.html",
    "chars": 502,
    "preview": "<html>\n  <head></head>\n  <body>\n    <script src=\"bower_components/react/react.js\"></script>\n    <script src=\"bower_compo"
  },
  {
    "path": "test/integration/bower.json",
    "chars": 375,
    "preview": "{\n  \"name\": \"integration\",\n  \"version\": \"0.4.1\",\n  \"homepage\": \"https://github.com/chenglou/react-motion\",\n  \"authors\": "
  },
  {
    "path": "test/integration/package.json",
    "chars": 340,
    "preview": "{\n  \"name\": \"integration\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"Simple folder for testing whether "
  },
  {
    "path": "test/mergeDiff-test.js",
    "chars": 3084,
    "preview": "import mergeDiff from '../src/mergeDiff';\n\nconst id = (_, s) => s;\nconst n = () => null;\n\n// helper to make the tests mo"
  },
  {
    "path": "test/stripStyle-test.js",
    "chars": 362,
    "preview": "import stripStyle from '../src/stripStyle';\nimport spring from '../src/spring';\n\ndescribe('stripStyle', () => {\n  it('sh"
  },
  {
    "path": "webpack.config.js",
    "chars": 1309,
    "preview": "'use strict';\n\nmodule.exports = {\n  mode: \"development\",\n  devtool:\n    process.env.NODE_ENV === 'development' ? 'eval-s"
  }
]

About this extraction

This page contains the full source code of the chenglou/react-motion GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 68 files (183.5 KB), approximately 53.2k tokens, and a symbol index with 162 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!