Socket
Socket
Sign inDemoInstall

react-smooth

Package Overview
Dependencies
50
Maintainers
2
Versions
53
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.3 to 0.0.4

src/AnimateGroup.js

15

CHANGELOG.md

@@ -1,11 +0,18 @@

### 0.0.3 / 2016-01-21
### 0.0.4 / 2016-02-02
===
- add libraryTarget to webpack.config.js
- fix: support onAnimationEnd in js animation
### 0.0.2 / 2016-01-21
### 0.0.3 / 2016-02-02
===
- add files to package.json
- refactor: refactor the import path of lodash function
- chore: update webpack.config.js
### 0.0.2 / 2016-02-02
===
- feat: support js animation
- feat: support bezier and spring timing function
- feat: support group animation
### 0.0.1 / 2016-01-21
===
- Init the project
{
"name": "react-smooth",
"version": "0.0.3",
"version": "0.0.4",
"description": "react animation library",

@@ -30,12 +30,18 @@ "main": "src/index.js",

"homepage": "https://github.com/recharts/react-smooth#readme",
"peerDependencies": {
"react": "0.14.6",
"react-dom": "0.14.6"
},
"dependencies": {
"babel-register": "^6.4.3",
"pure-render-decorator": "^0.2.0",
"react": "^0.14.6",
"react-dom": "^0.14.6"
"invariant": "2.2.0",
"lodash": "4.1.0",
"pure-render-decorator": "0.2.0",
"raf": "3.1.0",
"react-addons-transition-group": "0.14.6"
},
"devDependencies": {
"babel-core": "^6.4.5",
"babel-eslint": "^5.0.0-beta6",
"babel-loader": "^6.2.1",
"babel-register": "6.4.3",
"babel-core": "6.4.5",
"babel-eslint": "5.0.0-beta6",
"babel-loader": "6.2.1",
"babel-plugin-transform-decorators-legacy": "1.3.4",

@@ -47,18 +53,20 @@ "babel-plugin-transform-export-extensions": "6.3.13",

"babel-preset-stage-0": "6.3.13",
"chai": "^3.4.1",
"eslint": "^1.10.3",
"eslint-config-airbnb": "^3.1.0",
"eslint-plugin-react": "^3.15.0",
"karma": "^0.13.19",
"karma-mocha": "^0.2.1",
"karma-phantomjs-launcher": "^0.2.3",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.7.0",
"mocha": "^2.3.4",
"phantomjs": "^1.9.18",
"react-addons-test-utils": "^0.14.6",
"webpack": "^1.12.11",
"webpack-dev-server": "^1.14.1"
"chai": "3.4.1",
"eslint": "1.10.3",
"eslint-config-airbnb": "3.1.0",
"eslint-plugin-react": "3.15.0",
"karma": "0.13.19",
"karma-mocha": "0.2.1",
"karma-phantomjs-launcher": "0.2.3",
"karma-sourcemap-loader": "0.3.7",
"karma-webpack": "1.7.0",
"mocha": "2.3.4",
"phantomjs": "1.9.18",
"react": "0.14.7",
"react-addons-test-utils": "0.14.6",
"react-dom": "0.14.7",
"webpack": "1.12.11",
"webpack-dev-server": "1.14.1"
},
"license": "MIT"
}

@@ -14,2 +14,4 @@ # react-smooth

## Usage
ordinary animation
```jsx

@@ -20,4 +22,5 @@ <Animate to="0" attributeName="opacity">

```
or
```js
steps animation
```jsx
const steps = [{

@@ -40,5 +43,3 @@ style: {

}];
```
```jsx
<Animate steps={steps}>

@@ -48,6 +49,62 @@ <div />

```
children can be a function
```jsx
<Animate from={{ opacity: 0 }}
to={{ opacity: 1 }}
easing="ease-in"
>
{
({ opacity }) => <div style={{ opacity }}></div>
}
</Animate>
```
you can configure js timing function
```js
const easing = configureEasing('linear');
const easing = configureEasing('spring');
const easing = configureEasing('ease-in-out');
const easing = configureBezier(0.1, 0.1, 0.5, 0.8);
const easing = configureSpring({ stiff: 170, damping: 20 });
```
group animation
```jsx
const appear = {
from: 0,
to: 1,
attributeName: 'opacity',
};
const leave = {
steps: [{
moment: 0,
style: {
transform: 'translateX(0)',
},
}, {
moment: 1000,
style: {
transform: 'translateX(300)',
height: 50,
},
}, {
moment: 2000,
style: {
height: 0,
},
}]
}
<AnimateGroup appear={appear} leave={leave}>
{ list }
</AnimateGroup>
```
## API
### props
### Animate

@@ -133,2 +190,35 @@ <table class="table table-bordered table-striped">

### AnimateGroup
<table class="table table-bordered table-striped animate-group">
<thead>
<tr>
<th style="width: 40px">name</th>
<th style="width: 40px">type</th>
<th style="width: 40px">default</th>
<th style="width: 100px">description</th>
</tr>
</thead>
<tbody>
<tr>
<td>appear</td>
<td>object</td>
<td>undefined</td>
<td>configure element appear animation</td>
</tr>
<tr>
<td>enter</td>
<td>object</td>
<td>undefined</td>
<td>configure element appear animation</td>
</tr>
<tr>
<td>leave</td>
<td>object</td>
<td>undefined</td>
<td>configure element appear animation</td>
</tr>
</tbody>
</table>
## License

@@ -135,0 +225,0 @@

import React, { Component, PropTypes, cloneElement, Children } from 'react';
import createAnimateManager from './AnimateManager';
import pureRender from 'pure-render-decorator';
import { getDashCase, debug, getIntersectionKeys } from './util';
import omit from 'lodash/fp/omit';
import { configEasing } from './easing';
import configUpdate from './configUpdate';
import isEqual from 'lodash/isEqual';
import { getDashCase, getIntersectionKeys } from './util';

@@ -17,12 +21,15 @@ @pureRender

begin: PropTypes.number,
easing: PropTypes.string,
easing: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
steps: PropTypes.arrayOf(PropTypes.shape({
moment: PropTypes.number.isRequired,
style: PropTypes.object.isRequired,
easing: PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear']),
// dash case type animation css properties
easing: PropTypes.oneOfType([
PropTypes.oneOf(['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear']),
PropTypes.func,
]),
// transition css properties(dash case), optional
properties: PropTypes.arrayOf('string'),
onAnimationEnd: PropTypes.func,
})),
children: PropTypes.node,
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
isActive: PropTypes.bool,

@@ -49,6 +56,11 @@ canBegin: PropTypes.bool,

const { isActive, attributeName, from, to, steps } = this.props;
const { isActive, attributeName, from, to, steps, children } = this.props;
if (!isActive) {
this.state = {};
// if children is a function and animation is not active, set style to 'to'
if (typeof children === 'function') {
this.state = { style: to };
}
return;

@@ -60,2 +72,9 @@ }

} else if (from) {
if (typeof children === 'function') {
this.state = {
style: from,
};
return;
}
this.state = {

@@ -70,2 +89,8 @@ style: attributeName ? { [attributeName]: from } : from,

componentDidMount() {
const { isActive, canBegin } = this.props;
if (!isActive || !canBegin) {
return;
}
this.runAnimation(this.props);

@@ -75,9 +100,56 @@ }

componentWillReceiveProps(nextProps) {
if (!this.props.canBegin && nextProps.canBegin) {
this.runAnimation(nextProps);
const { isActive, canBegin } = nextProps;
if (!isActive || !canBegin) {
return;
}
const omitSpec = omit(['children', 'onAnimationEnd']);
if (isEqual(omitSpec(this.props), omitSpec(nextProps))) {
return;
}
if (this.manager) {
this.manager.stop();
}
if (this.stopJSAnimation) {
this.stopJSAnimation();
}
this.runAnimation(nextProps);
}
runStepAnimation() {
const { steps } = this.props;
componentWillUnmount() {
if (this.manager) {
this.manager.stop();
this.manager = null;
}
if (this.stopJSAnimation) {
this.stopJSAnimation();
}
}
runJSAnimation(props) {
const { from, to, duration, easing, begin, onAnimationEnd } = props;
const render = style => this.setState({ style });
const startAnimation = configUpdate(from, to, configEasing(easing), duration, render);
const finalStartAnimation = () => {
this.stopJSAnimation = startAnimation();
};
this.manager.start([
from,
begin,
finalStartAnimation,
duration,
onAnimationEnd,
]);
}
runStepAnimation(props) {
const { steps } = props;
const { style: initialStyle, moment: initialTime } = steps[0];

@@ -101,4 +173,13 @@

getIntersectionKeys(preItem.style, style).map(getDashCase);
const duration = moment - preItem.moment;
const duration = moment - preItem.moment;
if (typeof easing === 'function') {
return [...sequence, this.runJSAnimation.bind(this, {
from: preItem.style,
to: style,
duration,
easing,
}), duration];
}
const transition = properties.map(prop => {

@@ -109,3 +190,4 @@ return `${prop} ${duration}ms ${easing}`;

const newStyle = {
...nextItem.style,
...preItem.style,
...style,
transition,

@@ -123,6 +205,6 @@ };

return this.manager.setStyle(
return this.manager.start(
[
...steps.reduce(addStyle, [initialStyle, initialTime]),
this.props.onAnimationEnd,
props.onAnimationEnd,
]

@@ -136,5 +218,3 @@ );

}
const {
canBegin,
begin,

@@ -146,14 +226,15 @@ duration,

easing,
isActive,
onAnimationEnd,
steps,
children,
} = props;
if (!isActive || !canBegin) {
const manager = this.manager;
manager.subscribe(::this.handleStyleChange);
if (typeof easing === 'function' || typeof children === 'function' || easing === 'spring') {
this.runJSAnimation(props);
return;
}
const manager = this.manager;
manager.subscribe(::this.handleStyleChange);
const from = attributeName ? { [attributeName]: propsFrom } : propsFrom;

@@ -163,3 +244,3 @@ const to = attributeName ? { [attributeName]: propsTo } : propsTo;

if (steps.length > 1) {
this.runStepAnimation(steps);
this.runStepAnimation(props);
return;

@@ -172,3 +253,3 @@ }

manager.setStyle([from, begin, { ...to, transition }, duration, onAnimationEnd]);
manager.start([from, begin, { ...to, transition }, duration, onAnimationEnd]);
}

@@ -178,3 +259,2 @@

const style = this.manager.getStyle();
console.log(style);
this.setState({ style });

@@ -196,18 +276,33 @@ }

} = this.props;
const container = Children.only(children);
// todo: set animation to all children
const { style = {}, className } = container.props;
const count = Children.count(children);
if (!isActive) {
if (typeof children === 'function') {
return children(this.state.style);
}
if (!isActive || count === 0) {
return children;
}
return cloneElement(container, {
...others,
style: {
...this.state.style,
...style,
},
className,
});
const cloneContainer = container => {
const { style = {}, className } = container.props;
const res = cloneElement(container, {
...others,
style: {
...style,
...this.state.style,
},
className,
});
return res;
};
if (count === 1) {
const onlyChild = Children.only(children);
return cloneContainer(Children.only(children));
}
return <div>{Children.map(children, child => cloneContainer(child))}</div>;
}

@@ -214,0 +309,0 @@ }

@@ -1,3 +0,3 @@

import { translateStyle, debugf } from './util';
import { compose } from './util';
import { translateStyle } from './util';
import compose from 'lodash/fp/compose';

@@ -7,2 +7,3 @@ const createAnimateManager = initialStyle => {

let handleChange = () => {};
let shouldStop = false;

@@ -17,3 +18,10 @@ return {

},
start: () => {
shouldStop = false;
},
getShouldStop: () => shouldStop,
getStyle: () => currStyle,
stop: () => {
shouldStop = true;
},
};

@@ -29,4 +37,4 @@ };

var middlewareAPI = {
getStyle: manager.getStyle,
setStyle: (action) => setStyle(action),
...manager,
setStyle: (_style) => setStyle(_style),
};

@@ -39,2 +47,6 @@ chain = middlewares.map(middleware => middleware(middlewareAPI));

setStyle,
start: (_style) => {
manager.start();
return setStyle(_style);
},
};

@@ -44,23 +56,35 @@ };

const setStyleAsync = ({ setStyle }) => next => style => {
if (typeof style === 'function' || Array.isArray(style)) {
return next(style);
}
const setStyleAsync = ({ setStyle, getShouldStop }) => next => {
let timeout = null;
return new Promise((resolve, reject) => {
let timeout = 0;
let callback = next;
return style => {
if (getShouldStop()) {
clearTimeout(timeout);
if (typeof style === 'number') {
timeout = style;
callback = () => {};
return new Promise((resolve, reject) => {
reject();
});
}
setTimeout(() => {
const res = callback(style);
resolve();
if ((typeof style === 'function' || Array.isArray(style))) {
return next(style);
}
return res;
}, timeout);
});
return new Promise((resolve, reject) => {
let delay = 0;
let callback = next;
if (typeof style === 'number') {
delay = style;
callback = () => {};
}
timeout = setTimeout(() => {
const res = callback(style);
resolve();
return res;
}, delay);
});
};
};

@@ -75,3 +99,3 @@

return setStyle(currStyle);
}),
}).catch(() => {}),
Promise.resolve()

@@ -92,2 +116,11 @@ );

/*
* manager.setStyle:
* if style is an object, manager will set a new style.
* if style is a number, manager will wait time of style microsecond.
* if style is a function, manager will run this function bind arguments of
* getStyle and setStyle.
* if style is an array, manager will run setStyle of every element in order.
*/
const finalCreateAniamteManager = compose(

@@ -94,0 +127,0 @@ applyMiddleware(setStyleAsync, sequenceMiddleware, thunkMiddeware)

import Animate from './Animate';
import { configBezier, configSpring, configEasing } from './easing';
import AnimateGroup from './AnimateGroup';
export { configSpring, configBezier, configEasing, AnimateGroup };
export default Animate;

@@ -0,81 +1,8 @@

import intersection from 'lodash/intersection';
const PREFIX_LIST = ['Webkit', 'Moz', 'O', 'ms'];
const IN_COMPATIBLE_PROPERTY = ['transform', 'transformOrigin', 'transition'];
export const __ = {
'@@functional/placeholder': true,
};
const isPlaceHolder = val => val === __;
const _curry0 = (fn) => {
return function _curried(...args) {
if (args.length === 0 || args.length === 1 && isPlaceHolder(args[0])) {
return _curried;
}
return fn(...args);
};
};
const curryN = (n, fn) => {
if (n === 1) {
return fn;
}
return _curry0((...args) => {
const argsLength = args.filter(arg => arg !== __).length;
if (argsLength >= n) {
return fn(...args);
}
return curryN(n - argsLength, _curry0((...restArgs) => {
const newArgs = args.map(arg =>
isPlaceHolder(arg) ? restArgs.shift() : arg
);
return fn(...newArgs, ...restArgs);
}));
});
};
export const curry = fn => {
return curryN(fn.length, fn);
};
export const compose = (...args) => {
if (!args.length) {
return identity;
}
const fns = args.reverse();
// first function can receive multiply arguments
const firstFn = fns[0];
const tailsFn = fns.slice(1);
return (...composeArgs) =>
tailsFn.reduce((res, fn) =>
fn(res),
firstFn(...composeArgs)
);
};
const keys = obj => Object.keys(obj);
const intersection = (preArr, nextArr) => {
let res = [];
for (let i = 0, preLength = preArr.length; i < preLength; ++i) {
for (let j = 0, nextLength = nextArr.length; j < nextLength; ++j) {
if (preArr[i] === nextArr[j]) {
res = [...res, preArr[i]];
break;
}
}
}
return res;
};
export const getIntersectionKeys = (preObj, nextObj) => {
return intersection(keys(preObj), keys(nextObj));
return intersection(Object.keys(preObj), Object.keys(nextObj));
};

@@ -126,3 +53,3 @@

*/
export const debugf = (f, tag) => (...args) => {
export const debugf = (tag, f) => (...args) => {
const res = f(...args);

@@ -138,12 +65,19 @@ const name = tag || f.name || 'anonymous function';

/*
* @description: checks if the input style property need add compatible style prefix
* @description: check if the received property need add compatible style prefix
* string => boolean
*/
export const containsNeedTranslated = key => IN_COMPATIBLE_PROPERTY.indexOf(key) !== -1;
export const judgeNeedTranslated = property => IN_COMPATIBLE_PROPERTY.indexOf(property) !== -1;
/*
* @description: log name, args, return value of a function
* (string, any) => object
* @description: map object on every element in this object.
* (function, object) => object
*/
export const toObj = ([key, val]) => ({ [key]: val });
export const mapObject = (fn, obj) => {
return Object.keys(obj).reduce((res, key) => {
return {
...res,
[key]: fn(key, obj[key]),
};
}, {});
};

@@ -154,12 +88,5 @@ /*

*/
const mapObj = curry((fn, obj) =>
Object.keys(obj).map(key =>
obj[key]
).map(fn)
);
export const translateStyle = style => {
return Object.keys(style).reduce((res, key) => {
if (containsNeedTranslated(key)) {
if (judgeNeedTranslated(key)) {
return {

@@ -166,0 +93,0 @@ ...res,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc