Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #9 from twitter-fabric/release-packaging
Browse files Browse the repository at this point in the history
Prep for 1.0.0 release
  • Loading branch information
fionawhim committed Sep 28, 2015
2 parents b7e99c7 + a986400 commit 1f28e55
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 52 deletions.
133 changes: 130 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,138 @@ $ npm run demo
Visit <http://localhost:8080/webpack-dev-server/> in your browser. Hot reloading is enabled, if you
want to tweak the code in main.jsx.

## Requirements

The `VelocityComponent` and `VelocityTransitionGroup` components, as well as the `velocityHelpers`
utilities, are provided as ES5-compatible JavaScript files with [CommonJS](http://www.commonjs.org/)
`require` statements. You will need a dependency tool such as [Browserify](http://browserify.org/),
[RequireJS](http://requirejs.org/), or [webpack](https://webpack.github.io/) to use them.

This package depends directly on Velocity, as well as [lodash](https://lodash.com/) for a handful
of utility functions (which are required individually to try and keep bundle size down).

It is assumed that your application already depends on React. The `VelocityTransitionGroup`
component particularly requires the React addons at version 0.13 or higher.

## Usage

TODO(phopkins): Documentation
### `VelocityComponent`

Component to add Velocity animations to one or more children. Wraps a single child without adding
additional DOM nodes.

#### Example
```JSX
<VelocityComponent animation={{ opacity: this.state.showSubComponent ? 1 : 0 }} duration={500}>
<MySubComponent/>
</VelocityComponent>
```

#### Details

The API attempts to be as declarative as possible. A single `animation` property declares what
animation the child should have. If that property changes, this component applies the new animation
to the child on the next tick.

By default, the animation is not run when the component is mounted. Instead, Velocity's `finish`
command is used to jump to the animation's end state. For a component that animates out of and
back in to a default state, this allows the parent to specify the "animate into" animation as
the default, and therefore not have to distinguish between the initial state and the state to
return to after animating away.

#### Properties

`animation`: Either an animation key or hash defining the animation. See Velocity's documentation
for what this can be. (It is passed to Velocity exactly.)

`runOnMount`: If true, runs the animation even when the component is first mounted.

`targetQuerySelector`: By default, this component's single child is animated. If `targetQuerySelector`
is provided, it is used to select descendants to apply the animation to. Use with caution, only
when you're confident that React's reconcilliation will preserve these nodes during animation.
Also note `querySelectorAll`'s [silly behavior](http://ejohn.org/blog/thoughts-on-queryselectorall/) w.r.t. pruning results when being called on a node.
A special value of "children" will use the direct children of the node, since there isn't a
great way to specify that to `querySelectorAll`.

Unrecognized properties are passed as options to Velocity (e.g. `duration`, `delay`, `loop`).

#### Methods

`runAnimation`: Triggers the animation immediately. Useful for when you want an animation that
corresponds to an event but not a particular model state change (e.g. a "bump" when a click
occurs).


### `VelocityTransitionGroup`

Component to add Velocity animations around React transitions. Delegates to the React `TransitionGroup`
addon.

#### Example
```JSX
<VelocityTransitionGroup enter={{animation: "slideDown"}} leave={{animation: "slideUp"}}>
{this.state.renderSubComponent ? <MySubComponent/> : undefined}
</VelocityTransitionGroup>
```

#### Properties
`enter`: Animation to run on a child component being added

`leave`: Animation to run on a child component leaving

`runOnMount`: if true, runs the `enter` animation on the elements that exist as children when this
component is mounted.

Any additional properties (e.g. `className`, `component`) will be passed to the internal
`TransitionGroup`.

`enter` and `leave` should either be a string naming an animation registered with UI Pack, or a hash
with an `animation` key that can either be a string itself, or a hash of style attributes to animate
(this value is passed to Velocity its the first arg).

If `enter` or `leave` is a hash, it can additionally have a `style` value that is applied the tick
before the Velocity animation starts. Use this for non-animating properties (like `position`) that
are prerequisites for correct animation. The style value is applied using Velocity's JS -> CSS
routines, which may differ from React's.

Any hash entries beyond `animation` and `style` are passed in an options hash to Velocity. Use this
for options like `stagger`, `reverse`, *&tc.*

#### Statics

`disabledForTest`: Set this to true globally to turn off all custom animation logic. Instead, this
component will behave like a vanilla TransitionGroup`.

### `velocityHelper`

#### `registerEffect`

Takes a Velocity "UI pack effect" definition and registers it with a unique key, returning that
key (to later pass as a value for the `animation` property). Takes an optional `suffix`, which can
be "In" or "Out" to modify UI Pack's behavior.

Unlike what you get from passing a style hash to `VelocityComponent`'s `animation` property,
Velocity "UI pack effects" can have chained animation calls and specify a `defaultDuration`, and
also can take advantage of `stagger` and `reverse` properties on the `VelocityComponent`.

You will need to manually register the UI Pack with the global Velocity in your application with:
```JS
require('velocity');
require('velocity-animate/velocity.ui');
```

See: (http://julian.com/research/velocity/#uiPack)

## Bugs
Please report any bugs to: <https://github.com/twitter-fabric/velocity-react/issues>

## Acknowledgments
Thanks to Julian Shapiro and Ken Wheeler for creating and maintaining Velocity, respectively,
and for working with us to release this library.

### VelocityComponent
Thanks to Kevin Robinson and Sam Phillips for all of the discussions and code reviews.

### VelocityTransitionGroup
## License
Copyright 2015 Twitter, Inc.

Licensed under the MIT License: https://opensource.org/licenses/MIT
28 changes: 19 additions & 9 deletions demo/components/loading-crossfade-component.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
// Component for a VelocityTransitionGroup that crossfades between its children.

//
// To use this component, render with a single child that contains the "loading" version of your
// UI. When data has loaded, switch the "key" of this child so that React considers it a brand
// new element and triggers the enter / leave effects. The two versions of the UI are expected to
// have identical heights.

// Properties on this component are applied to the VelocityTransitionGroup component that this
// delegates to. A postion: 'relative' style is also applied since the loading effect requires
// position: 'absolute' on the child.

//
// Properties on this component (such as "style") are applied to the VelocityTransitionGroup
// component that this delegates to. We set the VelocityTransitionGroup's container to a <div> by
// default, and provide enter and leave animations, though these could be overridden if it makes
// sense for your use case. A postion: 'relative' style is also applied by default since the loading
// effect requires position: 'absolute' on the child.
//
// This component defines a "duration" property that is used for both the enter and leave animation
// durations.
//
// Use the property "opaque" if the children have opaque backgrounds. This will make the new element
// come in 100% opacity and fade the old element out from on top of it. (Without this, opaque
// elements end up bleeding the background behind the LoadingCrossfadeComponent through.)

var React = require('react');
var _ = require('lodash');
var VelocityTransitionGroup = require('../../lib/velocity-transition-group');
var VelocityTransitionGroup = require('../../velocity-transition-group');

var LoadingCrossfadeComponent = React.createClass({
displayName: 'LoadingCrossfadeComponent',

propTypes: {
opaque: React.PropTypes.bool,
duration: React.PropTypes.number,
// At most 1 child should be supplied at a time, though the animation does correctly handle
// elements moving in and out faster than the duration (so you can have 2 leaving elements
// simultaneously, for example).
children: React.PropTypes.element,
},

getDefaultProps: function () {
Expand All @@ -32,10 +41,11 @@ var LoadingCrossfadeComponent = React.createClass({
},

render: function () {
// position: 'relative' lets us absolutely-position the leaving child during the fade.
// We pull style out explicitly so that we can merge the position: 'relative' over any provided
// value. position: 'relative' lets us absolutely-position the leaving child during the fade.
var style = _.defaults((this.props.style || {}), { position: 'relative' });

var transitionGroupProps = _.defaults(_.omit(this.props, 'children', 'style'), {
var transitionGroupProps = _.defaults(_.omit(this.props, _.keys(this.constructor.propTypes), 'style'), {
component: 'div',
style: style,

Expand Down
35 changes: 19 additions & 16 deletions demo/examples/crossfade-example.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
var _ = require('lodash');

var React = require('react');
var VelocityComponent = require('../../lib/velocity-component');
var VelocityTransitionGroup = require('../../lib/velocity-transition-group');
var VelocityHelpers = require('../../lib/velocity-helpers');
var VelocityComponent = require('../../velocity-component');
var VelocityTransitionGroup = require('../../velocity-transition-group');

var Box = require('../components/box');
var EmojiSpan = require('../components/emoji-span');
Expand Down Expand Up @@ -71,15 +70,16 @@ var CrossfadeExample = React.createClass({

render: function () {
var groupStyle = {
width: 198,
borderBottom: '1px solid #3f83b7',
padding: '0 1px',
};

var boxStyle = {
margin: '-10px 0 0 0',
width: '100%',
};

var toggleStyle = {
width: 200,
backgroundColor: '#3f83b7',
color: 'white',
padding: 8,
Expand All @@ -94,21 +94,23 @@ var CrossfadeExample = React.createClass({
};

return (
<div className="flex-box flex-1 flex-column align-items-center" style={boxStyle}>
<div className="flex-box justify-content-space-between" style={toggleStyle} onClick={this.whenToggleClicked}>
<div className="flex-box flex-1 flex-column align-items-stretch" style={boxStyle}>
<div className="flex-box justify-content-space-between user-select-none" style={toggleStyle} onClick={this.whenToggleClicked}>
Points of Interest
<VelocityComponent animation={{rotateZ: this.state.expanded ? 0 : -180}} duration={this.state.duration}>
<EmojiSpan style={arrowStyle}>👇</EmojiSpan>
</VelocityComponent>
</div>

<VelocityTransitionGroup component="div" className="flex-1" style={groupStyle}
enter={{animation: 'slideDown', duration: this.state.duration}}
leave={{animation: 'slideUp', duration: this.state.duration}}>
{this.state.expanded ? this.renderLocations() : null}
</VelocityTransitionGroup>
<div className="flex-1">
<VelocityTransitionGroup component="div" style={groupStyle}
enter={{animation: 'slideDown', duration: this.state.duration, style: {height: ''}}}
leave={{animation: 'slideUp', duration: this.state.duration}}>
{this.state.expanded ? this.renderLocations() : null}
</VelocityTransitionGroup>
</div>

<form style={{fontSize: 12}}>
<form style={{fontSize: 12, textAlign: 'center'}}>
<label>
<input type="radio" name="speed" value={500} checked={this.state.duration === 500} onChange={this.whenOptionClicked}/> Fast
</label>
Expand All @@ -125,12 +127,13 @@ var CrossfadeExample = React.createClass({
var boxStyle = {
backgroundColor: '#fefefe',
padding: '5px 10px',
width: 198,
};

var locations = this.state.items != null ? this.state.items : Array.apply(null, Array(LOCATION_COUNT));

return (
<LoadingCrossfadeComponent duration={this.state.duration * .75}>
<LoadingCrossfadeComponent duration={this.state.duration * .75} key="content">
<div key={this.state.items != null ? 'locations' : 'loading'} style={boxStyle}>{locations.map(this.renderLocation)}</div>
</LoadingCrossfadeComponent>
);
Expand All @@ -156,8 +159,8 @@ var CrossfadeExample = React.createClass({
};

return (
<div className="flex-box align-items-center" style={rowStyle}>
<EmojiSpan key={i}
<div className="flex-box align-items-center" style={rowStyle} key={i}>
<EmojiSpan
className={location.city == '' ? 'loading-placeholder-dark loading-placeholder-full' : ''}
style={emojiStyle}>{location.building}</EmojiSpan>
<div style={cityStyle} className={'flex-1 ' + (location.city == '' ? 'loading-placeholder-dark loading-placeholder-full' : '')}>
Expand Down
12 changes: 6 additions & 6 deletions demo/examples/flap-box.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var _ = require('lodash');
var React = require('react');
var VelocityComponent = require('../../lib/velocity-component');
var VelocityHelpers = require('../../lib/velocity-helpers');
var VelocityComponent = require('../../velocity-component');
var velocityHelpers = require('../../velocity-helpers');

var Box = require('../components/box');
var EmojiSpan = require('../components/emoji-span');
Expand All @@ -16,7 +16,7 @@ on a state value.
var FlipAnimations = {
// Brings the box from flipped up to down. Also the default state that the box starts in. When
// this animates, includes a little swing at the end so it feels more like a flap.
down: VelocityHelpers.registerEffect({
down: velocityHelpers.registerEffect({
// longer due to spring timing
defaultDuration: 1100,
calls: [
Expand All @@ -36,7 +36,7 @@ var FlipAnimations = {
}),

// Flips the box up nearly 180°.
up: VelocityHelpers.registerEffect({
up: velocityHelpers.registerEffect({
defaultDuration: 200,
calls: [
[{
Expand All @@ -57,14 +57,14 @@ var FlipAnimations = {
// immediately with no tweening, since that doesn't make sense for the effect. We're using
// Velocity here only to co-ordinate the timing of the change.
var BlurAnimations = {
blur: VelocityHelpers.registerEffect({
blur: velocityHelpers.registerEffect({
defaultDuration: 200,
calls: [
[{ blur: [3, 3], opacity: [.4, .4] }, 1, { delay: 50 }],
],
}),

unblur: VelocityHelpers.registerEffect({
unblur: velocityHelpers.registerEffect({
defaultDuration: 200,
calls: [
[{ blur: [0, 0], opacity: [1, 1] }, 1, { delay: 150 }],
Expand Down
8 changes: 4 additions & 4 deletions demo/examples/scrolling-group.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var React = require('react');
var VelocityTransitionGroup = require('../../lib/velocity-transition-group');
var VelocityHelpers = require('../../lib/velocity-helpers');
var VelocityTransitionGroup = require('../../velocity-transition-group');
var velocityHelpers = require('../../velocity-helpers');

var Box = require('../components/box');
var EmojiSpan = require('../components/emoji-span');
Expand All @@ -11,7 +11,7 @@ var FOODS = ['🍅', '🍆', '🍇', '🍈', '🍉', '🍊', '🍌', '🍍', '

var Animations = {
// Register these with UI Pack so that we can use stagger later.
In: VelocityHelpers.registerEffect({
In: velocityHelpers.registerEffect({
calls: [
[{
transformPerspective: [ 800, 800 ],
Expand All @@ -27,7 +27,7 @@ var Animations = {
],
}),

Out: VelocityHelpers.registerEffect({
Out: velocityHelpers.registerEffect({
calls: [
[{
transformPerspective: [ 800, 800 ],
Expand Down
2 changes: 1 addition & 1 deletion demo/examples/toggle-box.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var React = require('react');
var VelocityComponent = require('../../lib/velocity-component');
var VelocityComponent = require('../../velocity-component');
var tweenState = require('react-tween-state');
var s = require('underscore.string');

Expand Down
2 changes: 1 addition & 1 deletion demo/examples/trigger-box.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var React = require('react');
var VelocityComponent = require('../../lib/velocity-component');
var VelocityComponent = require('../../velocity-component');
var s = require('underscore.string');

var Box = require('../components/box');
Expand Down
7 changes: 3 additions & 4 deletions demo/main.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
require('./css/flexbox.css');

var React = require('react');
var VelocityComponent = require('../lib/velocity-component');
var VelocityTransitionGroup = require('../lib/velocity-transition-group');

require('velocity-animate');
require('velocity-animate/velocity.ui');

var CrossfadeExample = require('./examples/crossfade-example');
var FlapBox = require('./examples/flap-box');
var ScrollingGroup = require('./examples/scrolling-group');
var ToggleBox = require('./examples/toggle-box');
var TriggerBox = require('./examples/trigger-box');

require('velocity-animate/velocity.ui');

var Demo = React.createClass({
render: function () {
var boxStyle = {
Expand Down
Loading

0 comments on commit 1f28e55

Please sign in to comment.