react-multi-carousel
Advanced tools
Comparing version 1.1.9 to 1.2.0
@@ -14,8 +14,12 @@ import * as React from "react"; | ||
componentDidMount(): void; | ||
setClones(slidesToShow: number, itemWidth?: number, forResizing?: boolean): void; | ||
setItemsToShow(shouldCorrectItemPosition?: boolean): void; | ||
setContainerAndItemWidth(slidesToShow: number, shouldCorrectItemPosition?: boolean): void; | ||
correctItemsPosition(itemWidth: number): void; | ||
onResize(): void; | ||
componentDidUpdate({ keyBoardControl, autoPlay }: CarouselProps, { containerWidth }: CarouselInternalState): void; | ||
resetAllItems(): void; | ||
onResize(value?: any): void; | ||
componentDidUpdate({ keyBoardControl, autoPlay }: CarouselProps, { containerWidth, domLoaded, isSliding }: CarouselInternalState): void; | ||
correctClonesPosition({ domLoaded, isSliding }: { | ||
domLoaded?: boolean; | ||
isSliding?: boolean; | ||
}): void; | ||
next(slidesHavePassed?: number): void; | ||
@@ -37,4 +41,6 @@ previous(slidesHavePassed?: number): void; | ||
getIfSlideIsVisbile(index: number): boolean; | ||
getServerSideState(): any; | ||
renderCarouselItems(): any; | ||
render(): React.ReactNode; | ||
} | ||
export default Carousel; |
@@ -5,4 +5,4 @@ "use strict"; | ||
const utils_1 = require("./utils"); | ||
const defaultTransitionDuration = 300; | ||
const defaultTransition = "transform 300ms ease-in-out"; | ||
const defaultTransitionDuration = 400; | ||
const defaultTransition = "transform 400ms ease-in-out"; | ||
class Carousel extends React.Component { | ||
@@ -16,2 +16,3 @@ constructor(props) { | ||
currentSlide: 0, | ||
clones: React.Children.toArray(props.children), | ||
totalItems: React.Children.count(props.children), | ||
@@ -21,4 +22,6 @@ deviceType: "", | ||
transform: 0, | ||
containerWidth: 0 | ||
containerWidth: 0, | ||
isSliding: false | ||
}; | ||
const { infinite, transitionDuration } = props; | ||
this.onResize = this.onResize.bind(this); | ||
@@ -30,4 +33,11 @@ this.handleDown = this.handleDown.bind(this); | ||
this.handleEnter = this.handleEnter.bind(this); | ||
this.next = this.next.bind(this); | ||
this.previous = this.previous.bind(this); | ||
/* | ||
The reason of using throttle its because of cloning elemnts for inifinite mode. | ||
*/ | ||
this.next = infinite | ||
? utils_1.throttle(this.next.bind(this), props.transitionDuration || defaultTransitionDuration) | ||
: this.next.bind(this); | ||
this.previous = infinite | ||
? utils_1.throttle(this.previous.bind(this), props.transitionDuration || defaultTransitionDuration) | ||
: this.previous.bind(this); | ||
this.getIfSlideIsVisbile = this.getIfSlideIsVisbile.bind(this); | ||
@@ -37,3 +47,3 @@ this.onMove = false; | ||
this.lastPosition = 0; | ||
this.isAnimationAllowed = true; | ||
this.isAnimationAllowed = false; | ||
this.direction = ""; | ||
@@ -45,3 +55,3 @@ } | ||
window.addEventListener("resize", this.onResize); | ||
this.onResize(); | ||
this.onResize(true); | ||
if (this.props.keyBoardControl) { | ||
@@ -54,4 +64,16 @@ window.addEventListener("keyup", this.onKeyUp); | ||
} | ||
setClones(slidesToShow, itemWidth, forResizing) { | ||
this.isAnimationAllowed = false; | ||
const childrenArr = React.Children.toArray(this.props.children); | ||
const { clones, initialSlide } = utils_1.getClones(this.state.slidesToShow, childrenArr); | ||
this.setState({ | ||
clones, | ||
totalItems: clones.length, | ||
currentSlide: forResizing ? this.state.currentSlide : initialSlide | ||
}, () => { | ||
this.correctItemsPosition(itemWidth || this.state.itemWidth); | ||
}); | ||
} | ||
setItemsToShow(shouldCorrectItemPosition) { | ||
const { responsive } = this.props; | ||
const { responsive, infinite } = this.props; | ||
Object.keys(responsive).forEach(item => { | ||
@@ -73,2 +95,6 @@ const { breakpoint, items } = responsive[item]; | ||
itemWidth | ||
}, () => { | ||
if (this.props.infinite) { | ||
this.setClones(slidesToShow, itemWidth, shouldCorrectItemPosition); | ||
} | ||
}); | ||
@@ -81,5 +107,2 @@ if (shouldCorrectItemPosition) { | ||
correctItemsPosition(itemWidth) { | ||
if (!this.isAnimationAllowed) { | ||
this.isAnimationAllowed = true; | ||
} | ||
this.setState({ | ||
@@ -89,6 +112,22 @@ transform: -(itemWidth * this.state.currentSlide) | ||
} | ||
onResize() { | ||
this.setItemsToShow(); | ||
onResize(value) { | ||
// value here can be html event or a boolean. | ||
// if its in infinite mode, we want to keep the current slide index no matter what. | ||
// if its not infinite mode, keeping the current slide index has already been taken care of | ||
const { infinite } = this.props; | ||
let shouldCorrectItemPosition; | ||
if (!infinite) { | ||
shouldCorrectItemPosition = false; | ||
} | ||
else { | ||
if (typeof value === "boolean" && value) { | ||
shouldCorrectItemPosition = false; | ||
} | ||
else { | ||
shouldCorrectItemPosition = true; | ||
} | ||
} | ||
this.setItemsToShow(shouldCorrectItemPosition); | ||
} | ||
componentDidUpdate({ keyBoardControl, autoPlay }, { containerWidth }) { | ||
componentDidUpdate({ keyBoardControl, autoPlay }, { containerWidth, domLoaded, isSliding }) { | ||
if (this.containerRef && | ||
@@ -111,19 +150,27 @@ this.containerRef.current && | ||
} | ||
if (this.props.infinite) { | ||
this.correctClonesPosition({ domLoaded, isSliding }); | ||
} | ||
} | ||
resetAllItems() { | ||
const { afterChanged, beforeChanged } = this.props; | ||
const previousSlide = this.state.currentSlide; | ||
if (typeof beforeChanged === "function") { | ||
beforeChanged(0, this.getState()); | ||
} | ||
this.setState({ transform: 0, currentSlide: 0 }, () => { | ||
if (typeof afterChanged === "function") { | ||
correctClonesPosition({ domLoaded, isSliding }) { | ||
const childrenArr = React.Children.toArray(this.props.children); | ||
const { hasEnterClonedAfter, hasEnterClonedBefore, nextSlide, nextPosition } = utils_1.whenEnteredClones(this.state, childrenArr); | ||
if ( | ||
// this is to prevent this gets called on the server-side. | ||
this.state.domLoaded && | ||
domLoaded && | ||
isSliding && | ||
!this.state.isSliding) { | ||
if (hasEnterClonedAfter || hasEnterClonedBefore) { | ||
this.isAnimationAllowed = false; | ||
setTimeout(() => { | ||
afterChanged(previousSlide, this.getState()); | ||
this.setState({ | ||
transform: nextPosition, | ||
currentSlide: nextSlide | ||
}); | ||
}, this.props.transitionDuration || defaultTransitionDuration); | ||
} | ||
}); | ||
} | ||
} | ||
next(slidesHavePassed = 0) { | ||
this.isAnimationAllowed = true; | ||
const { slidesToShow } = this.state; | ||
@@ -143,6 +190,9 @@ const { slidesToSlide, infinite, afterChanged, beforeChanged } = this.props; | ||
} | ||
this.isAnimationAllowed = true; | ||
this.setState({ | ||
isSliding: true, | ||
transform: nextPosition, | ||
currentSlide: nextSlides | ||
}, () => { | ||
this.setState({ isSliding: false }); | ||
if (typeof afterChanged === "function") { | ||
@@ -163,6 +213,9 @@ setTimeout(() => { | ||
} | ||
this.isAnimationAllowed = true; | ||
this.setState({ | ||
isSliding: true, | ||
transform: maxPosition, | ||
currentSlide: maxSlides | ||
}, () => { | ||
this.setState({ isSliding: false }); | ||
if (typeof afterChanged === "function") { | ||
@@ -176,9 +229,6 @@ setTimeout(() => { | ||
else { | ||
if (infinite) { | ||
this.resetAllItems(); | ||
} | ||
return; | ||
} | ||
} | ||
previous(slidesHavePassed = 0) { | ||
this.isAnimationAllowed = true; | ||
const { slidesToShow } = this.state; | ||
@@ -193,6 +243,9 @@ const { slidesToSlide, infinite, afterChanged, beforeChanged } = this.props; | ||
} | ||
this.isAnimationAllowed = true; | ||
this.setState({ | ||
isSliding: true, | ||
transform: nextPosition, | ||
currentSlide: nextSlides | ||
}, () => { | ||
this.setState({ isSliding: false }); | ||
if (typeof afterChanged === "function") { | ||
@@ -210,6 +263,9 @@ setTimeout(() => { | ||
} | ||
this.isAnimationAllowed = true; | ||
this.setState({ | ||
isSliding: true, | ||
transform: 0, | ||
currentSlide: 0 | ||
}, () => { | ||
this.setState({ isSliding: false }); | ||
if (typeof afterChanged === "function") { | ||
@@ -229,6 +285,9 @@ setTimeout(() => { | ||
} | ||
this.isAnimationAllowed = true; | ||
this.setState({ | ||
isSliding: true, | ||
transform: maxPosition, | ||
currentSlide: maxSlides | ||
}, () => { | ||
this.setState({ isSliding: false }); | ||
if (typeof afterChanged === "function") { | ||
@@ -281,3 +340,6 @@ setTimeout(() => { | ||
if (this.onMove) { | ||
if (this.initialPosition > clientX) { | ||
const slidesHavePassedRight = Math.round((this.initialPosition - this.lastPosition) / this.state.itemWidth); | ||
const slidesHavePassedLeft = Math.round((this.lastPosition - this.initialPosition) / this.state.itemWidth); | ||
if (this.initialPosition > clientX && | ||
slidesHavePassedRight <= this.state.slidesToShow) { | ||
this.direction = "right"; | ||
@@ -294,3 +356,4 @@ const translateXLimit = Math.abs(-(this.state.itemWidth * | ||
} | ||
if (clientX > this.initialPosition) { | ||
if (clientX > this.initialPosition && | ||
slidesHavePassedLeft <= this.state.slidesToShow) { | ||
this.direction = "left"; | ||
@@ -321,3 +384,5 @@ const nextTranslate = this.state.transform + (clientX - this.lastPosition); | ||
this.props.minimumTouchDrag) { | ||
this.next(slidesHavePassed); | ||
this.next(slidesHavePassed > this.state.slidesToShow | ||
? this.state.slidesToShow | ||
: slidesHavePassed); | ||
} | ||
@@ -332,3 +397,5 @@ else { | ||
this.props.minimumTouchDrag) { | ||
this.previous(slidesHavePassed); | ||
this.previous(slidesHavePassed > this.state.slidesToShow | ||
? this.state.slidesToShow | ||
: slidesHavePassed); | ||
} | ||
@@ -363,2 +430,4 @@ else { | ||
} | ||
this.isAnimationAllowed = true; | ||
// getCounterPart() | ||
this.setState({ | ||
@@ -415,17 +484,22 @@ currentSlide: slide, | ||
renderDotsList() { | ||
const { customDot, dotListClassName } = this.props; | ||
return (React.createElement("ul", { className: `react-multi-carousel-dot-list ${dotListClassName}` }, Array(this.state.totalItems) | ||
const { customDot, dotListClassName, infinite } = this.props; | ||
// getPureItemsWithoutClone | ||
const childrenArr = React.Children.toArray(this.props.children); | ||
return (React.createElement("ul", { className: `react-multi-carousel-dot-list ${dotListClassName}` }, Array(childrenArr.length) | ||
.fill(0) | ||
.map((item, index) => { | ||
const slideIndex = infinite | ||
? utils_1.getCounterPart(index, this.state, childrenArr) | ||
: index; | ||
if (customDot) { | ||
return React.cloneElement(customDot, { | ||
index, | ||
onClick: () => this.goToSlide(index), | ||
index: slideIndex, | ||
onClick: () => this.goToSlide(slideIndex), | ||
carouselState: this.getState() | ||
}); | ||
} | ||
return (React.createElement("li", { key: index, className: `react-multi-carousel-dot ${this.state.currentSlide === index | ||
return (React.createElement("li", { key: index, className: `react-multi-carousel-dot ${this.state.currentSlide === slideIndex | ||
? "react-multi-carousel-dot--active" | ||
: ""}` }, | ||
React.createElement("button", { onClick: () => this.goToSlide(index) }))); | ||
React.createElement("button", { onClick: () => this.goToSlide(slideIndex) }))); | ||
}))); | ||
@@ -437,5 +511,5 @@ } | ||
} | ||
render() { | ||
getServerSideState() { | ||
const { domLoaded, slidesToShow, containerWidth, itemWidth } = this.state; | ||
const { deviceType, responsive, forSSR, children, slidesToSlide, removeArrow, removeArrowOnDeviceType, infinite, containerClassName, contentClassName, itemClassName, customTransition, partialVisbile } = this.props; | ||
const { deviceType, responsive, forSSR, partialVisbile } = this.props; | ||
let flexBisis; | ||
@@ -447,2 +521,39 @@ const domFullyLoaded = domLoaded && slidesToShow && containerWidth && itemWidth; | ||
const shouldRenderOnSSR = forSSR && deviceType && !domFullyLoaded && flexBisis; | ||
const paritialVisibilityGutter = utils_1.getParitialVisibilityGutter(responsive, partialVisbile, deviceType, this.state.deviceType); | ||
return { | ||
shouldRenderOnSSR, | ||
flexBisis, | ||
domFullyLoaded, | ||
paritialVisibilityGutter | ||
}; | ||
} | ||
renderCarouselItems() { | ||
const { itemWidth } = this.state; | ||
const { children, infinite, itemClassName, partialVisbile } = this.props; | ||
const { flexBisis, shouldRenderOnSSR, domFullyLoaded, paritialVisibilityGutter } = this.getServerSideState(); | ||
if (infinite) { | ||
return this.state.clones.map((child, index) => (React.createElement("li", { key: index, "aria-hidden": this.getIfSlideIsVisbile(index) ? "false" : "true", style: { | ||
flex: shouldRenderOnSSR ? `1 0 ${flexBisis}%` : "auto", | ||
position: "relative", | ||
width: domFullyLoaded | ||
? `${partialVisbile && paritialVisibilityGutter | ||
? itemWidth - paritialVisibilityGutter | ||
: itemWidth}px` | ||
: "auto" | ||
}, className: itemClassName }, child))); | ||
} | ||
return React.Children.toArray(children).map((child, index) => (React.createElement("li", { key: index, "aria-hidden": this.getIfSlideIsVisbile(index) ? "false" : "true", style: { | ||
flex: shouldRenderOnSSR ? `1 0 ${flexBisis}%` : "auto", | ||
position: "relative", | ||
width: domFullyLoaded | ||
? `${partialVisbile && paritialVisibilityGutter | ||
? itemWidth - paritialVisibilityGutter | ||
: itemWidth}px` | ||
: "auto" | ||
}, className: itemClassName }, child))); | ||
} | ||
render() { | ||
const { slidesToShow } = this.state; | ||
const { deviceType, slidesToSlide, removeArrow, removeArrowOnDeviceType, infinite, containerClassName, contentClassName, customTransition, partialVisbile } = this.props; | ||
const { shouldRenderOnSSR, paritialVisibilityGutter } = this.getServerSideState(); | ||
const isLeftEndReach = !(this.state.currentSlide - slidesToSlide >= 0); | ||
@@ -458,3 +569,2 @@ const isRightEndReach = !(this.state.currentSlide + 1 + slidesToShow <= | ||
const disableRightArrow = !infinite && isRightEndReach; | ||
const paritialVisibilityGutter = utils_1.getParitialVisibilityGutter(responsive, partialVisbile, deviceType, this.state.deviceType); | ||
// this is the perfect formular, the perfect code. | ||
@@ -480,15 +590,3 @@ const currentTransform = paritialVisibilityGutter && partialVisbile | ||
transform: `translate3d(${currentTransform}px,0,0)` | ||
}, onMouseMove: this.handleMove, onMouseDown: this.handleDown, onMouseUp: this.handleOut, onMouseEnter: this.handleEnter, onMouseLeave: this.handleOut, onTouchStart: this.handleDown, onTouchMove: this.handleMove, onTouchEnd: this.handleOut }, React.Children.toArray(children).map((child, index) => (React.createElement("li", { key: index, style: { | ||
flex: shouldRenderOnSSR ? `1 0 ${flexBisis}%` : "auto", | ||
position: "relative", | ||
width: domFullyLoaded | ||
? `${partialVisbile && paritialVisibilityGutter | ||
? itemWidth - paritialVisibilityGutter | ||
: itemWidth}px` | ||
: "auto" | ||
}, className: itemClassName }, React.cloneElement(child, { | ||
index, | ||
isvisible: this.getIfSlideIsVisbile(index), | ||
carouselState: this.getState() | ||
}))))), | ||
}, onMouseMove: this.handleMove, onMouseDown: this.handleDown, onMouseUp: this.handleOut, onMouseEnter: this.handleEnter, onMouseLeave: this.handleOut, onTouchStart: this.handleDown, onTouchMove: this.handleMove, onTouchEnd: this.handleOut }, this.renderCarouselItems()), | ||
shouldShowArrows && !disableLeftArrow && this.renderLeftArrow(), | ||
@@ -495,0 +593,0 @@ shouldShowArrows && !disableRightArrow && this.renderRightArrow(), |
@@ -61,3 +61,5 @@ /// <reference types="react" /> | ||
transform: number; | ||
isSliding?: boolean; | ||
clones: any[]; | ||
} | ||
export { CarouselInternalState, CarouselProps, responsiveType, stateCallBack, buttonGroupCallBack }; |
@@ -1,4 +0,18 @@ | ||
import { responsiveType } from "./types"; | ||
import { responsiveType, CarouselInternalState } from "./types"; | ||
declare function guessWidthFromDeviceType(deviceType: string, responsive: responsiveType): number | string | undefined; | ||
declare function getParitialVisibilityGutter(responsive: responsiveType, partialVisbile?: string | boolean, serverSideDeviceType?: string | undefined, clientSideDeviceType?: string | undefined): number | undefined; | ||
export { guessWidthFromDeviceType, getParitialVisibilityGutter }; | ||
declare function getCounterPart(index: number, { slidesToShow }: { | ||
slidesToShow: number; | ||
}, childrenArr: any[]): number; | ||
declare function getClones(slidesToShow: number, childrenArr: any[]): { | ||
clones: any[]; | ||
initialSlide: number; | ||
}; | ||
declare function whenEnteredClones({ currentSlide, slidesToShow, itemWidth, totalItems }: CarouselInternalState, childrenArr: any[]): { | ||
hasEnterClonedAfter: boolean; | ||
hasEnterClonedBefore: boolean; | ||
nextSlide: number; | ||
nextPosition: number; | ||
}; | ||
declare const throttle: (func: any, limit: number) => any; | ||
export { guessWidthFromDeviceType, getParitialVisibilityGutter, getClones, whenEnteredClones, throttle, getCounterPart }; |
@@ -21,2 +21,83 @@ "use strict"; | ||
exports.getParitialVisibilityGutter = getParitialVisibilityGutter; | ||
function getCounterPart(index, { slidesToShow }, childrenArr) { | ||
if (childrenArr.length > slidesToShow * 2) { | ||
const originalFirstSlide = childrenArr.length - (childrenArr.length - slidesToShow * 2); | ||
return originalFirstSlide + index; | ||
} | ||
else { | ||
return childrenArr.length + index; | ||
} | ||
} | ||
exports.getCounterPart = getCounterPart; | ||
function getClones(slidesToShow, childrenArr) { | ||
let initialSlide; | ||
let clones; | ||
if (childrenArr.length > slidesToShow * 2) { | ||
clones = [ | ||
...childrenArr.slice(childrenArr.length - slidesToShow * 2, childrenArr.length), | ||
...childrenArr, | ||
...childrenArr.slice(0, slidesToShow * 2) | ||
]; | ||
initialSlide = slidesToShow * 2; | ||
} | ||
else { | ||
clones = [...childrenArr, ...childrenArr, ...childrenArr]; | ||
initialSlide = childrenArr.length; | ||
} | ||
return { | ||
clones, | ||
initialSlide | ||
}; | ||
} | ||
exports.getClones = getClones; | ||
function whenEnteredClones({ currentSlide, slidesToShow, itemWidth, totalItems }, childrenArr) { | ||
let nextSlide = 0; | ||
let nextPosition = 0; | ||
let hasEnterClonedAfter; | ||
const hasEnterClonedBefore = currentSlide === 0; | ||
const originalFirstSlide = childrenArr.length - (childrenArr.length - slidesToShow * 2); | ||
if (childrenArr.length > slidesToShow * 2) { | ||
hasEnterClonedAfter = | ||
currentSlide >= originalFirstSlide + childrenArr.length; | ||
if (hasEnterClonedAfter) { | ||
nextSlide = originalFirstSlide; | ||
nextPosition = -(itemWidth * nextSlide); | ||
} | ||
if (hasEnterClonedBefore) { | ||
nextSlide = originalFirstSlide + (childrenArr.length - slidesToShow * 2); | ||
nextPosition = -(itemWidth * nextSlide); | ||
} | ||
} | ||
else { | ||
hasEnterClonedAfter = currentSlide >= childrenArr.length * 2; | ||
if (hasEnterClonedAfter) { | ||
nextSlide = currentSlide - childrenArr.length; | ||
nextPosition = -(itemWidth * nextSlide); | ||
} | ||
if (hasEnterClonedBefore) { | ||
nextSlide = totalItems - slidesToShow * 2; | ||
nextPosition = -(itemWidth * nextSlide); | ||
} | ||
} | ||
return { | ||
hasEnterClonedAfter, | ||
hasEnterClonedBefore, | ||
nextSlide, | ||
nextPosition | ||
}; | ||
} | ||
exports.whenEnteredClones = whenEnteredClones; | ||
const throttle = (func, limit) => { | ||
let inThrottle; | ||
return function () { | ||
const args = arguments; | ||
const context = this; | ||
if (!inThrottle) { | ||
func.apply(context, args); | ||
inThrottle = true; | ||
setTimeout(() => (inThrottle = false), limit); | ||
} | ||
}; | ||
}; | ||
exports.throttle = throttle; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "react-multi-carousel", | ||
"version": "1.1.9", | ||
"version": "1.2.0", | ||
"description": "", | ||
@@ -8,3 +8,2 @@ "main": "index.js", | ||
"scripts": { | ||
"preversion": "npm run test", | ||
"build": "rm -rf ./lib && tsc && npm run after-build", | ||
@@ -11,0 +10,0 @@ "test": "jest", |
@@ -184,22 +184,2 @@ # react-multi-carousel | ||
## The items you passed as children. | ||
All the items you passed as children will received a list of props and the current state that's passed back by the Carousel. | ||
This is useful if you want to support accessibility or do your own stuff. | ||
[An Example](https://w3js.com/react-multi-carousel/?selectedKind=Carousel&selectedStory=with%20aria%20hidden%2C%20inspect%20me%20in%20the%20debugger&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel). | ||
Inspect the element in the chrome debugger. | ||
``` | ||
const CarouselItem = ({ isvisible, currentSlide, onMove, ...rest }) => { | ||
console.log(rest); | ||
return <div aria-hidden={isvisible ? 'false':'true'} className={isvisible? 'special style' : 'normal style'}></div> | ||
} | ||
<Carousel> | ||
<CarouselItem /> | ||
<CarouselItem /> | ||
<CarouselItem /> | ||
</Carousel> | ||
``` | ||
## ParitialVisibile props. | ||
@@ -206,0 +186,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
109228
935
322