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 #8 from twitter-fabric/feature/crossfade-demo
Browse files Browse the repository at this point in the history
Crossfade example
  • Loading branch information
fionawhim committed Sep 23, 2015
2 parents 3e616bc + 0299ae2 commit b7e99c7
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 4 deletions.
4 changes: 3 additions & 1 deletion demo/components/emoji-span.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ var EmojiSpan = React.createClass({
},

render: function () {
let {children, size, ...attrs} = this.props;

return (
<span dangerouslySetInnerHTML={{__html: twemoji.parse(s.escapeHTML(this.props.children), {size: this.props.size})}} />
<span {...attrs} dangerouslySetInnerHTML={{__html: twemoji.parse(s.escapeHTML(children), {size: size})}} />
);
},
});
Expand Down
81 changes: 81 additions & 0 deletions demo/components/loading-crossfade-component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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.

// 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 LoadingCrossfadeComponent = React.createClass({
displayName: 'LoadingCrossfadeComponent',

propTypes: {
opaque: React.PropTypes.bool,
duration: React.PropTypes.number,
},

getDefaultProps: function () {
return {
duration: 350,
};
},

render: function () {
// 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'), {
component: 'div',
style: style,

enter: {
animation: { opacity: 1 },
duration: this.props.duration,
style: {
// If we're animating opaque backgrounds then we just render the new element under the
// old one and fade out the old one. Without this, at e.g. the crossfade midpoint of
// 50% opacity for old and 50% opacity for new, the parent background ends up bleeding
// through 25%, which makes things look not smooth at all.
opacity: this.props.opaque ? 1 : 0,

// We need to clear out all the styles that "leave" puts on the element.
position: 'relative',
top: '',
left: '',
bottom: '',
right: '',
zIndex: '',
},
},

leave: {
animation: { opacity: 0 },
duration: this.props.duration,
style: {
// 'absolute' so the 2 elements overlap for a crossfade
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
zIndex: 1,
},
},
});

return React.createElement(VelocityTransitionGroup, transitionGroupProps, this.props.children);
},
});

module.exports = LoadingCrossfadeComponent;
42 changes: 42 additions & 0 deletions demo/css/loading-placeholder.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.loading-placeholder-light,
.loading-placeholder-dark {
position: relative;
}

/* Gray, translucent bar to show "loading." Renders as 86% of the parent's height, vertically
centered, and 100% of its width. */
.loading-placeholder-light:before,
.loading-placeholder-dark:before {
content: ' ';
display: block;
position: absolute;
top: 7%;
height: 86%;
width: 100%;
}

.loading-placeholder-full:before {
top: 0;
height: 100%;
}

/* Inserts a non-breaking space into the parent to guarantee that it has at least one line's
worth of height. (Necessary for the 'before' block to do a relatively-sized height.) */
.loading-placeholder-light:after,
.loading-placeholder-dark:after {
content: '\00a0';
}

.loading-placeholder-light:before {
background-color: rgba(235, 237, 241, 0.1);
}

.loading-placeholder-dark:before {
background-color: rgba(235, 237, 241, 0.5);
}

span.loading-placeholder-light,
span.loading-placeholder-dark {
/* Useful for being able to set an explicit width on the placeholder. */
display: inline-block;
}
171 changes: 171 additions & 0 deletions demo/examples/crossfade-example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
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 Box = require('../components/box');
var EmojiSpan = require('../components/emoji-span');
var LoadingCrossfadeComponent = require('../components/loading-crossfade-component');

require('../css/loading-placeholder.css');

var LOCATION_COUNT = 4;

var BUILDINGS = ['🏠', '🏡', '🏢', '🏬', '🏭', '🏣', '🏤', '🏥', '🏦', '🏨', '🏩', '💒', '⛪', '🏪', '🏫'];
var CAPTIALS = ['Montgomery', 'Juneau', 'Phoenix', 'Little Rock', 'Sacramento', 'Denver', 'Hartford', 'Dover',
'Tallahassee', 'Atlanta', 'Honolulu', 'Boise', 'Springfield', 'Indianapolis', 'Des Moines', 'Topeka', 'Frankfort',
'Baton Rouge', 'Augusta', 'Annapolis', 'Boston', 'Lansing', 'St. Paul', 'Jackson', 'Jefferson City', 'Helena',
'Lincoln', 'Carson City', 'Concord', 'Trenton', 'Santa Fe', 'Albany', 'Raleigh', 'Bismarck', 'Columbus',
'Oklahoma City', 'Salem', 'Harrisburg', 'Providence', 'Columbia', 'Pierre', 'Nashville', 'Austin', 'Salt Lake City',
'Montpelier', 'Richmond', 'Olympia', 'Charleston', 'Madison', 'Cheyenne'];

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

getInitialState: function () {
return {
expanded: false,
items: null,
duration: 500,
};
},

componentWillUnmount: function () {
window.clearTimeout(this.locationTimeout);
},

whenToggleClicked: function () {
if (this.state.expanded) {
this.setState({
expanded: false,
items: null,
});

window.clearTimeout(this.locationTimeout);
} else {
this.setState({
expanded: true,
items: null,
});

this.locationTimeout = window.setTimeout(this.loadLocations, this.state.duration * 1.5);
}
},

loadLocations: function () {
this.setState({
items: Array.apply(null, Array(LOCATION_COUNT)).map(function () {
return {
building: _.sample(BUILDINGS),
city: _.sample(CAPTIALS),
};
}),
});
},

whenOptionClicked: function (event) {
this.setState({ duration: parseInt(event.target.value) });
},

render: function () {
var groupStyle = {
width: 198,
};

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

var toggleStyle = {
width: 200,
backgroundColor: '#3f83b7',
color: 'white',
padding: 8,
fontSize: 13,
lineHeight: '18px',
cursor: 'pointer',
};

var arrowStyle = {
display: 'block',
fontSize: 18,
};

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}>
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>

<form style={{fontSize: 12}}>
<label>
<input type="radio" name="speed" value={500} checked={this.state.duration === 500} onChange={this.whenOptionClicked}/> Fast
</label>
&nbsp;
<label>
<input type="radio" name="speed" value={2000} checked={this.state.duration === 2000} onChange={this.whenOptionClicked}/> Slow
</label>
</form>
</div>
);
},

renderLocations: function () {
var boxStyle = {
backgroundColor: '#fefefe',
padding: '5px 10px',
};

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

return (
<LoadingCrossfadeComponent duration={this.state.duration * .75}>
<div key={this.state.items != null ? 'locations' : 'loading'} style={boxStyle}>{locations.map(this.renderLocation)}</div>
</LoadingCrossfadeComponent>
);
},

renderLocation: function(location, i) {
location = location || {building: '', city: ''};

var emojiStyle = {
fontSize: 30,
display: 'block',
width: 34.5,
height: 31,
};

var rowStyle = {
padding: '5px 0',
};

var cityStyle = {
fontSize: 16,
margin: '0 0 0 5px',
};

return (
<div className="flex-box align-items-center" style={rowStyle}>
<EmojiSpan key={i}
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' : '')}>
{location.city}
</div>
</div>
);
}
});

module.exports = CrossfadeExample;
4 changes: 2 additions & 2 deletions demo/examples/scrolling-group.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,15 @@ var ScrollingGroup = React.createClass({
{rows}
</VelocityTransitionGroup>

<div style={{fontSize: 12}}>
<form style={{fontSize: 12}}>
<label>
<input type="radio" name="speed" value={500} checked={this.state.duration === 500} onChange={this.whenOptionClicked}/> Fast
</label>
&nbsp;
<label>
<input type="radio" name="speed" value={2000} checked={this.state.duration === 2000} onChange={this.whenOptionClicked}/> Slow
</label>
</div>
</form>
</div>
);
},
Expand Down
4 changes: 3 additions & 1 deletion demo/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var React = require('react');
var VelocityComponent = require('../lib/velocity-component');
var VelocityTransitionGroup = require('../lib/velocity-transition-group');

var CrossfadeExample = require('./examples/crossfade-example');
var FlapBox = require('./examples/flap-box');
var ScrollingGroup = require('./examples/scrolling-group');
var ToggleBox = require('./examples/toggle-box');
Expand Down Expand Up @@ -43,11 +44,12 @@ var Demo = React.createClass({
var MainComponent = React.createClass({
render: function () {
return (
<div className="flex-box">
<div className="flex-box flex-wrap">
<Demo title="Property Change"><ToggleBox/></Demo>
<Demo title="On Demand"><TriggerBox/></Demo>
<Demo title="Custom Animation"><FlapBox/></Demo>
<Demo title="Custom Transition Group"><ScrollingGroup/></Demo>
<Demo title="Crossfade"><CrossfadeExample/></Demo>
</div>
);
},
Expand Down

0 comments on commit b7e99c7

Please sign in to comment.