Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
react-motion
Advanced tools
react-motion is a popular library for creating animations in React applications. It leverages the physics-based animation approach to create smooth and natural transitions. The library is highly flexible and allows developers to animate various properties of their components with ease.
Basic Animation
This example demonstrates a basic animation where a div element moves horizontally from 0 to 100 pixels using the spring function.
```jsx
import React from 'react';
import { Motion, spring } from 'react-motion';
const BasicAnimation = () => (
<Motion defaultStyle={{ x: 0 }} style={{ x: spring(100) }}>
{style => <div style={{ transform: `translateX(${style.x}px)` }}>Hello World</div>}
</Motion>
);
export default BasicAnimation;
```
Staggered Motion
This example shows how to create a staggered animation where multiple items move one after another, creating a cascading effect.
```jsx
import React from 'react';
import { StaggeredMotion, spring } from 'react-motion';
const StaggeredAnimation = () => (
<StaggeredMotion
defaultStyles={[{ x: 0 }, { x: 0 }, { x: 0 }]}
styles={prevInterpolatedStyles => prevInterpolatedStyles.map((_, i) => {
return i === 0
? { x: spring(100) }
: { x: spring(prevInterpolatedStyles[i - 1].x) };
})}
>
{interpolatingStyles => (
<div>
{interpolatingStyles.map((style, i) => (
<div key={i} style={{ transform: `translateX(${style.x}px)` }}>Item {i}</div>
))}
</div>
)}
</StaggeredMotion>
);
export default StaggeredAnimation;
```
Transition Motion
This example demonstrates how to use TransitionMotion to animate the addition and removal of items in a list, with smooth transitions for entering and leaving elements.
```jsx
import React from 'react';
import { TransitionMotion, spring } from 'react-motion';
class TransitionAnimation extends React.Component {
state = { items: ['a', 'b', 'c'] };
willEnter() {
return { opacity: 0 };
}
willLeave() {
return { opacity: spring(0) };
}
render() {
return (
<TransitionMotion
styles={this.state.items.map(item => ({ key: item, style: { opacity: spring(1) } }))}
willEnter={this.willEnter}
willLeave={this.willLeave}
>
{interpolatedStyles => (
<div>
{interpolatedStyles.map(config => (
<div key={config.key} style={{ opacity: config.style.opacity }}>{config.key}</div>
))}
</div>
)}
</TransitionMotion>
);
}
}
export default TransitionAnimation;
```
react-spring is a spring-physics based animation library that is highly flexible and performant. It provides a more modern API compared to react-motion and supports hooks, making it a popular choice for new React projects.
framer-motion is a powerful animation library that offers a simple and declarative API for creating animations. It supports keyframes, spring animations, and gestures, and is known for its ease of use and rich feature set.
react-transition-group is a low-level animation library that provides more control over the animation lifecycle. It is often used for more complex animations where developers need fine-grained control over the transition states.
<Spring endValue={{val: 10}}>
{interpolated => <div>{interpolated.val}</div>}
</Spring>
Animate a counter to 10
, from whatever value it currently is. For more advanced usage, see below.
Npm:
npm install react-motion
Bower:
bower install react-motion
1998 Script Tag:
<script src="path/to/react-motion/build/react-motion.js"></script>
(Module exposed as ReactMotion
)
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 constant for your UI element, and let the magic of physics take care of the rest. This way, you don't have to worry about the more petty questions such as "what if the item's currently animating and is a position x
? How do I adjust my time and curve?". It also greatly simplifies an animation API since there's really not that much to set up.
This library also provides an alternative, more powerful API for React's TransitionGroup
.
let Demo = React.createClass({
getInitialState() {
return {open: false};
},
handleMouseDown() {
this.setState({open: !this.state.open});
},
render() {
return (
<div>
<button onMouseDown={this.handleMouseDown}>Toggle</button>
<Spring endValue={{val: this.state.open ? 400 : 0}}>
{interpolated =>
<div className="demo0-block" style={{
transform: `translate3d(${interpolated.val}px, 0, 0)`,
}} />
}
</Spring>
</div>
);
}
});
The library exports a Spring
, a TransitionSpring
and utils
.
Exposes a single prop, endValue
, which takes either an object, an array or a function that returns an object or an array.
Type: endValue: object | array | object -> (object | array)
.
endValue
can be of an arbitrary shape (but must stay the same shape from one render to the next). There are however 2 reserved keys: val
and config
. Say your initial data structure looks so:
{size: 10, top: 20}
You only want to animate size
. Indicate what value/entire sub-collection you want to animate by wrapping it:
{size: {val: 10}, top: 20}
When you pass this to endValue
, Spring
will traverse your data structure and animate size
based on the end value you provided and the speed/position. top
will be kept untouched. You receive the interpolated data structure as an argument to your children function:
<Spring endValue={{size: {val: 10}, top: 20}}>
{tweeningCollection => {
let style = {
width: tweeningCollection.size.val,
height: tweeningCollection.size.val,
top: tweeningCollection.top,
};
return <div style={style} />;
}}
</Spring>
Where the value of tweeningCollection
might be e.g. {size: {val: 3.578}, top: 20}
.
If, instead of passing a number to val
({val: 10}
), you pass an array or an object, by default Spring
will interpolate every number in it.
But lots of times you don't want all the values to animate the same way. You can pass a config
to specify the stiffness and the damping of the spring
:
{size: {val: 10, config: [120, 17]}, top: 20}
A stiffness of 120
and damping of 17
gives the spring a slight bounce effect. The default configuration, if you don't pass config
alongside val
, is [170, 26]
.
You can nest val
wrappers; the innermost takes priority:
{
val: {
size: {val: 10, config: [120, 17]},
top: 20,
left: 50
},
config: [100, 10]
}
Here, top
and left
will be animated with [stiffness, damping] of [100, 10]
, while size
will use [120, 17]
instead.
Sometimes you might have a data structure where you want to animate everything but one thing:
{
val: {
top: 20,
left: 50,
opacity: 1,
itemID: 19230,
}
}
This is wrong, since itemID
would accidentally animate too. You can of course do this:
{
top: {val: 20},
left: {val: 50},
opacity: {val: 1},
itemID: 19230,
}
But this is still slightly tedious. Here's an alternative:
{
val: {
top: 20,
left: 50,
opacity: 1,
itemID: {val: 19230, config: []},
}
}
Explicitly setting a config
of []
signals Spring
not to drill down that collection and animate.
Sometime, you want to rely on the currently interpolated value to calculate endValue
. E.g. (demo 1) a chat head's final position is the current position of the leading chat head. endValue
can also accept a function (currentPositions) => yourEndValue
, where currentPositions
is the same data structure you'd receive from the children callback.
// ...Somewhere in your React class
getEndValues: function(currentPositions) {
// currentPositions of `null` means it's the first render for Spring.
if (currentPositions == null) {
return {val: utils.range(6).map(() => [0, 0])};
}
// This is really the previous tick of currentPositions. In practice, it
// doesn't make much difference.
let endValue = currentPositions.val.map((_, i) => {
// First one follows the mouse
return i === 0 ? this.state.mousePosition : currentPositions.val[i - 1];
});
// Have fun adjusting config to make the chat heads bounce a little more!
return {val: endValue, config: [120, 17]};
},
Like Spring
, but can take two other props: willEnter
and willLeave
. Throughout this section, please remember that
endValue
: now constrained to an object (or a callback currentValue -> object
) of the shape {key => yourStuff}
(the data is constrained to this shape, but that doesn't mean the way you use your interpolated value has to be). When endValue
differs from the current interpolated value by an added/removed key:
willEnter
: a callback that's called once and is passed (keyThatEnters, correspondingValueOfKey, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)
. Return an object/array configuration that'll serve as the starting value of that new key. That configuration will be merged into endValue
. The default value of willEnter
is (key, endValue) => endValue[key]
. It returns the same configuration as the one you just specified in endValue
. In other words, the start and end are the same: no animation.
willLeave
: a callback that's called many times and is passed (keyThatLeaves, correspondingValueOfKeyThatJustLeft, endValueYouJustSpecified, currentInterpolatedValue, currentSpeed)
. Return an object/array configuration (which will serve as the new endValue[keyThatLeaves]
and merged into endValue
) to indicate you still want to keep the item around. Otherwise, return null
.
(See the demo files for fuller ones.)
let Demo = React.createClass({
getInitialState() {
return {
blocks: {
a: 'I am a',
b: 'I am b',
c: 'I am c',
},
};
},
getEndValue() {
let blocks = this.state.blocks;
let configs = {};
Object.keys(blocks).forEach(key => {
configs[key] = {
height: {val: 50},
opacity: {val: 1},
text: blocks[key], // interpolate the above 2 fields only
};
});
return configs;
},
willEnter(key) {
return {
height: {val: 50},
opacity: {val: 1},
text: this.state.blocks[key],
};
},
willLeave(key, value, endValue, currentValue, currentSpeed) {
if (currentValue[key].opacity.val === 0 && currentSpeed[key].opacity.val === 0) {
return null; // kill component when opacity reaches 0
}
return {
height: {val: 0},
opacity: {val: 0},
text: currentValue[key].text,
};
},
handleClick(key) {
let {...newBlocks} = this.state.blocks;
delete newBlocks[key];
this.setState({blocks: newBlocks});
},
render() {
return (
<TransitionSpring
endValue={this.getEndValue}
willEnter={this.willEnter}
willLeave={this.willLeave}>
{currentValue =>
<div>
{Object.keys(currentValue).map(key => {
let style = {
height: currentValue[key].height.val,
opacity: currentValue[key].opacity.val,
};
return (
<div onClick={this.handleClick.bind(null, key)} style={style}>
{currentValue[key].text}
</div>
);
})}
</div>
}
</TransitionSpring>
);
}
});
(You might not need this until later on.)
Since TransitionSpring
dictates endValue
to be an object, manipulating keys could be a little more tedious than manipulating arrays. Here are the common scenarios' solutions:
{newKey: myConfigForThisKey, ...oldConfigs}
.{...oldConfigs, newKey: myConfigForThisKey}
.utils.reorderKeys
function.utils.reorderKeys(object, newKeysFunction)
newKeysFunction
will receive, as arguments, the array of keys in object
and should return a new array of keys (with e.g. order changed and/or keys missing). reorderKeys
will then return a new object similar to object
, but with the keys in the order newKeysFunction
dictated.
FAQs
A spring that solves your animation problems.
We found that react-motion demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.