Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Fader component #7

Merged
merged 6 commits into from
Dec 8, 2014
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
99 changes: 8 additions & 91 deletions Carousel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,14 @@

var React = require("react");
var Swipable = require("../Swipable");
var range = require("../utils/range");
var CarouselMixin = require("../CarouselMixin");
var getClassName = require("../utils/getClassName");
var setPosition = require("../utils/setPosition").setPosition;
var noop = require("../utils/noop");

module.exports = React.createClass({
displayName: "Carousel",

mixins: [Swipable],

propTypes: {
baseClass: React.PropTypes.string,
cacheSize: React.PropTypes.number,
embedWidth: React.PropTypes.number,
embedHeight: React.PropTypes.number,
pageIndex: React.PropTypes.number,
previousPageIndex: React.PropTypes.number,
loop: React.PropTypes.bool,
renderEmptyPages: React.PropTypes.bool,
pages: React.PropTypes.arrayOf(React.PropTypes.any).isRequired,
pageView: React.PropTypes.func.isRequired,
onSwiped: React.PropTypes.func,
swipeThreshold: React.PropTypes.number,
swipeCancelThreshold: React.PropTypes.number,
},

getDefaultProps: function () {
return {
baseClass: "merry-go-round",
cacheSize: 1,
embedWidth: 0,
embedHeight: 0,
pageIndex: 0,
previousPageIndex: 0,
loop: false,
renderEmptyPages: false,
onSwiped: noop,
swipeThreshold: 10,
swipeCancelThreshold: 10,
};
},
mixins: [Swipable, CarouselMixin],

isMoving: function () {
return this.props.pageIndex !== this.props.previousPageIndex;
Expand All @@ -56,62 +23,12 @@ module.exports = React.createClass({
};
},

isIndexWithinBounds: function (index) {
return index >= 0 && index < this.props.pages.length;
},

normalizeIndex: function (index) {
if ( !this.props.loop ) { return index; }

while ( index < 0 ) {
index += this.props.pages.length;
}

return index % this.props.pages.length;
},

isIndexInView: function (index, viewIndex) {
return Math.abs(index - viewIndex) <= this.props.cacheSize;
},

calculateBuffers: function () {
var first = Math.min(this.props.previousPageIndex, this.props.pageIndex) - this.props.cacheSize;
var last = Math.max(this.props.previousPageIndex, this.props.pageIndex) + this.props.cacheSize;
var indices = range(first, last + 1);

return indices.map(function calculateBuffer (index) {
return {
index: index,
pageIndex: this.normalizeIndex(index),
willBeDiscarded: !this.isIndexInView(this.props.pageIndex, index),
isNew: !this.isIndexInView(this.props.previousPageIndex, index),
};
}.bind(this));
},

renderPages: function () {

var PageView = this.props.pageView;
var buffers = this.calculateBuffers();

return buffers.map(function renderBuffer (buffer) {
var pageView;

if ( this.props.renderEmptyPages || this.isIndexWithinBounds(buffer.pageIndex) ) {
pageView = PageView({
page: this.props.pages[buffer.pageIndex],
index: buffer.pageIndex,
willBeDiscarded: buffer.willBeDiscarded,
isNew: buffer.isNew,
});
}

return React.DOM.div({
className: this.props.baseClass + "__page",
key: buffer.index,
style: this.calculatePageStyle(buffer.index),
}, pageView);
}.bind(this));
renderPage: function (buffer, pageView) {
return React.DOM.div({
className: this.props.baseClass + "__page",
key: buffer.index,
style: this.calculatePageStyle(buffer.index),
}, pageView);
},

calculateSliderStyle: function () {
Expand Down
94 changes: 94 additions & 0 deletions CarouselMixin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use strict";

var React = require("react");
var range = require("../utils/range");
var noop = require("../utils/noop");

var CarouselMixin = {
propTypes: {
baseClass: React.PropTypes.string,
cacheSize: React.PropTypes.number,
embedWidth: React.PropTypes.number,
embedHeight: React.PropTypes.number,
pageIndex: React.PropTypes.number,
previousPageIndex: React.PropTypes.number,
loop: React.PropTypes.bool,
renderEmptyPages: React.PropTypes.bool,
pages: React.PropTypes.arrayOf(React.PropTypes.any).isRequired,
pageView: React.PropTypes.func.isRequired,
onSwiped: React.PropTypes.func,
swipeThreshold: React.PropTypes.number,
swipeCancelThreshold: React.PropTypes.number,
},

getDefaultProps: function () {
return {
baseClass: "merry-go-round",
cacheSize: 1,
embedWidth: 0,
embedHeight: 0,
pageIndex: 0,
previousPageIndex: 0,
loop: false,
renderEmptyPages: false,
onSwiped: noop,
swipeThreshold: 10,
swipeCancelThreshold: 10,
};
},

isIndexWithinBounds: function (index) {
return index >= 0 && index < this.props.pages.length;
},

normalizeIndex: function (index) {
if ( !this.props.loop ) { return index; }

while ( index < 0 ) {
index += this.props.pages.length;
}

return index % this.props.pages.length;
},

isIndexInView: function (index, viewIndex) {
return Math.abs(index - viewIndex) <= this.props.cacheSize;
},

calculateBuffers: function () {
var first = Math.min(this.props.previousPageIndex, this.props.pageIndex) - this.props.cacheSize;
var last = Math.max(this.props.previousPageIndex, this.props.pageIndex) + this.props.cacheSize;
var indices = range(first, last + 1);

return indices.map(function calculateBuffer (index) {
return {
index: index,
pageIndex: this.normalizeIndex(index),
willBeDiscarded: !this.isIndexInView(this.props.pageIndex, index),
isNew: !this.isIndexInView(this.props.previousPageIndex, index),
};
}.bind(this));
},

renderPages: function () {
var PageView = this.props.pageView;
var buffers = this.calculateBuffers();

return buffers.map(function renderBuffer (buffer) {
var pageView;

if ( this.props.renderEmptyPages || this.isIndexWithinBounds(buffer.pageIndex) ) {
pageView = PageView({
page: this.props.pages[buffer.pageIndex],
index: buffer.pageIndex,
willBeDiscarded: buffer.willBeDiscarded,
isNew: buffer.isNew,
});
}

return this.renderPage(buffer, pageView);
}.bind(this));
},
};

module.exports = CarouselMixin;
56 changes: 56 additions & 0 deletions Fader/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use strict";

var React = require("react");
var Swipable = require("../Swipable");
var CarouselMixin = require("../CarouselMixin");
var getClassName = require("../utils/getClassName");
var noop = require("../utils/noop");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like noop is not used anywhere in this file.


module.exports = React.createClass({
displayName: "Carousel",

mixins: [Swipable, CarouselMixin],

calculatePageStyle: function (index) {
return {
width: this.props.pageWidth + "px",
height: this.props.pageHeight + "px",
opacity: index === this.props.pageIndex ? "1.0" : "0.0",
};
},

renderPage: function (buffer, pageView) {
return React.DOM.div({
className: this.props.baseClass + "__page",
key: buffer.index,
style: this.calculatePageStyle(buffer.index),
}, pageView);
},

calculateStyle: function () {
return {
width: (this.props.width) + "px",
height: (this.props.height) + "px",
left: (-this.props.embedWidth) + "px",
top: (-this.props.embedHeight) + "px",
};
},

render: function () {
if ( this.props.pages.length === 0 ) {
// (jussi-kalliokoski): Nothing to render. Avoids infinite loop in calculateBuffers().
return React.DOM.div();
}

return React.DOM.div({
className: this.props.baseClass,
onTouchStart: this.handleTouchStart,
onTouchMove: this.handleTouchMove,
onTouchEnd: this.handleTouchEnd,
onTouchCancel: this.handleTouchCancel,
style: this.calculateStyle(),
},
this.renderPages()
);
},
});
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Courtesy of the test suite that's run on [BrowserStack](https://www.browserstack

## Usage

Merry-go-Round exposes two components, `Carousel` and `Container`:
Merry-go-Round exposes three components, `Carousel`, `Fader`, and `Container`:

### Carousel

Expand All @@ -70,6 +70,10 @@ var Carousel = require("merry-go-round/Carousel");
* `embedHeight` (Integer, optional, defaults to `0`): The number of pixels to "embed" into the vertically. Basically reverses the container's padding, so that you can have things such as partially revealed pages that come outside the margin.
* `renderEmptyPages` (Boolean, optional, defaults to `false`): Whether to render empty pages. This is useful when you want to have special views for pages that don't have any content.

### Fader

The Fader is otherwise identical to the Carousel component and implements the same API, but instead of vertically sliding the pages, the pages fade in and out.

### Container

The Container is a general purpose mixin for creating containers of the Carousels. It provides some useful functionality such as auto-rotation, marker-based page navigation and passing on the carousel-related events to your controller view.
Expand Down
2 changes: 2 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ var spawn = require("child_process").spawn;

var files = [
"./Carousel/index.js",
"./Fader/index.js",
"./CarouselMixin/index.js",
"./Container/index.js",
"./utils/*.js",
"./gulpfile.js",
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";

module.exports.Carousel = require("./Carousel");
module.exports.Fader = require("./Fader");
module.exports.Container = require("./Container");
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"files": [
"index.js",
"Carousel",
"Fader",
"Container",
"Swipable",
"CarouselMixin",
"utils"
],
"scripts": {
Expand Down