Skip to content

Commit

Permalink
latest
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Nov 12, 2017
1 parent 0dc6e46 commit e0e6e80
Show file tree
Hide file tree
Showing 26 changed files with 293 additions and 118 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- **[Pointer](https://popmotion.io/api/pointer):** Full support for mouse and multitouch inputs.

### Popmotion is:
- **Tiny:** At 9.5kb **max**, it's 75% smaller than GreenSock TweenMax. Everything is individually importable to crush those bytes!
- **Tiny:** At 10kb **max**, it's 75% smaller than GreenSock TweenMax. Everything is available as an individual import to save bytes!
- **Reactive:** Super-simple Rx-inspired API for subscribing to streams of animation events.
- **Composable:** All actions can be **delayed**, **staggered** **merged**, **crossfaded** and **chained**.
- **Cross-platform:** Runs on **IE9+**, plus **Node**-based environments like Arduino.
Expand All @@ -38,6 +38,7 @@ TODO
## Plugins
- [Draggable](/api/draggable)
- [Spinnable](/api/spinnable)
- [React](/api/react)

### [Get Started](https://popmotion.io/learn/get-started)
### [Full API documentation](https://popmotion.io/api)
12 changes: 6 additions & 6 deletions docs/api/plugins/react.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: React
description: Popmotion animation, tweening and input tracking - in React!
description: Popmotion animation and input tracking - in React!
category: plugins
---

# Popmotion x React

Popmotion x React provides a simple interface to bring Popmotion's animation and input-tracking capabilities to any React component.
Popmotion x React provides a declarative interface to use Popmotion's animation and input tracking with any React component.

It uses the "function as children" pattern, so you can create declarative interactions with the DOM, SVG, Three.js, A-Frame, Pixi... anything that has a React interface.
It uses the "function as children" pattern, so you can create declarative interactions with the DOM, SVG, Three.js, A-Frame, Pixi... anything that has a React wrapper available.

It also has support for [React TransitionGroup](https://github.com/reactjs/react-transition-group/) lifecycle methods.

Expand All @@ -18,13 +18,13 @@ It also has support for [React TransitionGroup](https://github.com/reactjs/react
npm install --save popmotion-react
```

## MotionValue
## `MotionValue`

The `MotionValue` component allows you to declaratively animate a single `value`, array of `value`s or object of `value`s.
The `MotionValue` component allows you to declaratively animate a single `value`.

### Usage

`MotionValue` is a simple state machine. You provide state transition handlers and it provides setters to your component. For instance:
`MotionValue` is a simple state machine. You provide state transition handlers that describe what animation should play when a state is set, and it provides setter functions to your component. For instance:

```javascript
import { tween } from 'popmotion';
Expand Down
23 changes: 16 additions & 7 deletions docs/api/reactions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ category: reactions

# Reaction

A **reaction** is a collection of `update`, `complete` and `error` functions that can also be subscribed to.
A **reaction** is a collection of `update`, `complete` and `error` functions.

The `reaction` and [`value`](/api/value) functions create reactions that can also be subscribed to by multiple other reactions, creating a **chain reaction**.

They also help manage actions: if a `reaction` or `value` is passed to a second `action`, the first one will automatically `stop`.

## Import

Expand All @@ -16,6 +20,16 @@ import { reaction } from 'popmotion';
import reaction from 'popmotion/reactions';
```

## Usage

```javascript
const foo = reaction();
foo.subscribe((v) => console.log(v));

tween().start(foo);
spring().start(foo); // This will stop `tween`
```

## Methods

### Reaction methods
Expand All @@ -24,16 +38,11 @@ import reaction from 'popmotion/reactions';

- `pipe(...funcs: Array<(v) => v)`: Returns a new reaction that will run `update` values through this sequence of functions.
- `subscribe(update | { update, complete, error })`: Returns a subscription.
- `stop()`: Stops current parent action.
- `while((v: any) => boolean)`: Returns a new reaction that will `complete` when the provided function returns `false`.

### Subscription methods

`value().subscribe()` returns:

- `unsubscribe()`

#### Chainable modifiers

Reactions share the same chainable modifiers as `action`.

See: [Action - Methods](/api/action#methods).
19 changes: 17 additions & 2 deletions docs/api/reactions/value.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ category: reactions

# Value

Tracks the state of a number and allows velocity queries.
A [reaction](/api/reactions) that tracks the state of a number and allows velocity queries.

## Import

Expand All @@ -28,7 +28,21 @@ myVal.subscribe(div.set('x'));

tween({ to: 500 }).start(divX);

setTimeout(() => console.log(divX.getVelocity()), 150);
setTimeout(() => console.log(() => {
physics({
velocity: divX.getVelocity()
}).start(divX); // This will automatically `stop` the tween
}), 150);
```

`value` can also handle objects and arrays:

```javascript
const foo = value({ x: 0, y: 0 });
const bar = value([0, 0]);

foo.getVelocity(); // { x: 0, y: 0 }
bar.getVelocity(); // [0, 0]
```

## Methods
Expand All @@ -40,6 +54,7 @@ setTimeout(() => console.log(divX.getVelocity()), 150);
- `get(): number`: Returns the current value state.
- `getVelocity: number`: Returns the current value velocity.
- `pipe(...funcs: Array<(v) => v)`: Returns a new reaction that will run `update` values through this sequence of functions.
- `stop()`: Stops parent action.
- `subscribe(update | { update, complete })`: Returns a subscription.
- `while((v: any) => boolean)`: Returns a new reaction that will `complete` when the provided function returns `false`.

Expand Down
2 changes: 1 addition & 1 deletion packages/popmotion-draggable/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
"babel-register": "^6.3.13"
},
"peerDependencies": {
"popmotion": "^8.0.6"
"popmotion": "^8.1.0"
}
}
2 changes: 1 addition & 1 deletion packages/popmotion-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@
"react-dom": "~15.5.3"
},
"dependencies": {
"popmotion": "^8.0.5"
"popmotion": "^8.1.0"
}
}
24 changes: 5 additions & 19 deletions packages/popmotion-react/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { value, composite } from 'popmotion';
import value from 'popmotion/reactions/value';

export class MotionValue extends React.Component {
static defaultProps = {
Expand All @@ -13,18 +13,14 @@ export class MotionValue extends React.Component {

const isCompositeValue = (typeof v !== 'number');

this.value = value(v);
this.valueState = initialState;
this.state = {
isCompositeValue,
v,
setRef: (ref) => {
if (ref !== null) this.ref = ref;
},
velocity: !isCompositeValue ? 0 : Object.keys(v)
.reduce((acc, key) => {
acc[key] = 0;
return acc;
}, {}),
velocity: this.value.getVelocity(),
state: this.valueState,
setStateTo: onStateChange ? Object.keys(onStateChange)
.reduce((acc, key) => {
Expand All @@ -51,7 +47,7 @@ export class MotionValue extends React.Component {
}

componentDidMount() {
const { v, isCompositeValue, setStateTo, state } = this.state;
const { v, setStateTo, state } = this.state;

const onValueUpdate = (value) => {
this.setState({
Expand All @@ -60,17 +56,7 @@ export class MotionValue extends React.Component {
});
};

this.value = !isCompositeValue
? value(v, onValueUpdate)
: composite(
Object.keys(v).reduce((acc, key) => {
acc[key] = value(v[key]);
return acc;
}, {}),
{
onUpdate: onValueUpdate
}
);
this.value.subscribe(onValueUpdate);

if (state && setStateTo) setStateTo[state]();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/popmotion-spinnable/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
"babel-register": "^6.3.13"
},
"peerDependencies": {
"popmotion": "^8.0.6"
"popmotion": "^8.1.0"
}
}
9 changes: 9 additions & 0 deletions packages/popmotion/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

Popmotion adheres to [Semantic Versioning](http://semver.org/).

## [8.0.12@beta] 2017-11-11

### Added
- `value` handles objects and arrays.
- `reaction` and `value` automatically stop previous action if used to start a new one.

### Fixed
- `composite` APIs now map return values to the provided object, rather than as a flat array.

## [8.0.11@beta] 2017-11-10

### Added
Expand Down
2 changes: 1 addition & 1 deletion packages/popmotion/dist/popmotion.global.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/popmotion/dist/popmotion.xl.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/popmotion/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "popmotion",
"version": "8.0.11",
"version": "8.0.12",
"description": "A functional, reactive motion library.",
"author": "Matt Perry",
"homepage": "https://popmotion.io",
Expand Down Expand Up @@ -42,7 +42,7 @@
"measure": "gzip -c dist/popmotion.global.min.js | wc -c",
"test": "jest",
"publish-beta": "npm publish --tag beta",
"clean": "git clean -fd -e node_modules/ -e lib/ -x ."
"clean": "git clean -fd -e node_modules/ -e lib/ src/ -x ."
},
"dependencies": {
"framesync": "^3.1.3",
Expand Down
2 changes: 0 additions & 2 deletions packages/popmotion/src/action/_tests/vector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('vector', () => {
return new Promise((resolve, reject) => {
va({ p: { x: 1, y: 2 } })
.start((v) => {
console.log(v);
(v.x === 1 && v.y === 2)
? resolve()
: reject('composite output incorrect');
Expand All @@ -26,7 +25,6 @@ describe('vector', () => {
return new Promise((resolve, reject) => {
va({ p: [0, 1, 2, 3, 4] })
.start((v) => {
console.log(v);
(v[0] === 0 && v[1] === 1 && v[2] === 2 && v[3] === 3 && v[4] === 4)
? resolve()
: reject('parallel output incorrect');
Expand Down
8 changes: 6 additions & 2 deletions packages/popmotion/src/action/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import Chainable from '../chainable';
import createObserver from '../observer';
import { ObserverCandidate } from '../observer/types';
import { ObserverCandidate, PartialObserver } from '../observer/types';
import { ActionInit, ActionProps, ColdSubscription } from './types';

export class Action extends Chainable<Action> {
create(props: ActionProps) {
return new Action(props);
}

start(observerCandidate: ObserverCandidate): ColdSubscription {
start(observerCandidate: ObserverCandidate = {}): ColdSubscription {
const { init, ...observerProps } = this.props;
const observer = createObserver(observerCandidate, observerProps);
const api = init(observer);
Expand All @@ -21,6 +21,10 @@ export class Action extends Chainable<Action> {
? { ...defaultSubscription, ...api }
: defaultSubscription;

if ((observerCandidate as PartialObserver).registerParent) {
(observerCandidate as PartialObserver).registerParent(subscription);
}

return subscription;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('physics', () => {
}).start((v) => i = v);
setTimeout(() => {
a.stop();
(i >= 100 && i <= 110) ? resolve() : reject();
(i >= 100 && i <= 110) ? resolve() : reject(i);
}, 1000);
});
});
Expand Down
Empty file.
20 changes: 20 additions & 0 deletions packages/popmotion/src/compositors/_tests/compositors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ describe('parallel', () => {
]);
});
});

it('should return a mapped version of the api', () => {
const foo = action(({ update }) => {
return {
test: () => 1
};
});
const api = parallel(foo, foo, foo).start();
expect(api.test()).toEqual([1, 1, 1]);
});
});

describe('composite', () => {
Expand All @@ -99,6 +109,16 @@ describe('composite', () => {
]);
});
});

it('should return a mapped version of the api', () => {
const foo = action(({ update }) => {
return {
test: () => 1
};
});
const api = composite({ x: foo, y: foo }).start();
expect(api.test()).toEqual({ x: 1, y: 1 });
});
});

describe('merge', () => {
Expand Down
37 changes: 20 additions & 17 deletions packages/popmotion/src/compositors/composite.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import multi from './multi';
import { Action } from '../action';
import parallel from './parallel';
import { ColdSubscription } from '../action/types';

type ActionMap = {
[key: string]: Action
Expand All @@ -9,23 +10,25 @@ type ValueMap = {
[key: string]: any
};

const composite = (actionMap: ActionMap) => {
const actionKeys = Object.keys(actionMap);
const numActions = actionKeys.length;
const output: ValueMap = actionKeys.reduce((o: ValueMap, key) => {
o[key] = 0;
return o;
}, {});
const actions = actionKeys.map((key) => actionMap[key]);
type ColdSubscriptionMap = {
[key: string]: ColdSubscription
};

return parallel(...actions)
.pipe((v: any[]) => {
for (let i = 0; i < numActions; i++) {
const key = actionKeys[i];
output[key] = v[i];
}
const composite = multi<ActionMap, ColdSubscriptionMap, ValueMap, string>({
getOutput: () => ({}),
getCount: (subs) => Object.keys(subs).length,
getFirst: (subs) => subs[Object.keys(subs)[0]],
mapApi: (subs, methodName) => (...args) => Object.keys(subs)
.reduce((output: ValueMap, propKey: string) => {
if (subs[propKey][methodName]) output[propKey] = subs[propKey][methodName](...args);
return output;
});
};
}, {}),
setProp: (output, name, v) => output[name] = v,
startActions: (actions, starter) => Object.keys(actions)
.reduce((subs: ColdSubscriptionMap, key) => {
subs[key] = starter(actions[key], key);
return subs;
}, {})
});

export default composite;
Loading

0 comments on commit e0e6e80

Please sign in to comment.