4
diff --git a/gulpfile.js b/gulpfile.js
index 30ac0ea..9cdbb5f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -59,6 +59,11 @@ gulp.task(
gulp.series(["watch", "copy", "sass"], function() {
console.log("Start");
var myConfig = require("./webpack.config");
+ if (process.env.SINGLE_DEMO) {
+ myConfig.entry = {
+ "docs.js": "./docs/single-demo.js"
+ };
+ }
myConfig.plugins = myConfig.plugins.concat(
new webpack.DefinePlugin({
"process.env": {
@@ -73,11 +78,11 @@ gulp.task(
stats: {
colors: true
}
- }).listen(DEV_PORT, "localhost", function(err, result) {
+ }).listen(DEV_PORT, "0.0.0.0", function(err, result) {
if (err) {
console.log(err);
} else {
- const server_url = `http://localhost:${DEV_PORT}`;
+ const server_url = `http://0.0.0.0:${DEV_PORT}`;
console.log(`> Dev Server started at ${server_url}`);
opn(server_url);
}
diff --git a/package.json b/package.json
index 23eae81..a823e46 100644
--- a/package.json
+++ b/package.json
@@ -9,8 +9,11 @@
],
"scripts": {
"start": "gulp server",
- "build": "gulp clean && gulp sass && gulp copy && webpack",
- "prepublish": "babel ./src --out-dir ./lib && gulp dist",
+ "demo": "SINGLE_DEMO=true gulp server",
+ "build-dev": "gulp clean && gulp sass && gulp copy && webpack",
+ "lib": "babel ./src --out-dir ./lib",
+ "build": "npm run lib && gulp dist",
+ "prepublish": "npm run build",
"test": "npm run lint && jest",
"test:watch": "jest --watch",
"update-snapshots": "jest --updateSnapshot",
@@ -43,11 +46,11 @@
"autoprefixer": "^7.1.2",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^9.0.0",
- "babel-jest": "^23.4.2",
+ "babel-jest": "^24.8.0",
"babel-loader": "^8.0.4",
"babel-preset-airbnb": "^2.1.1",
"changelog-verify": "^1.1.2",
- "css-loader": "^0.28.0",
+ "css-loader": "^2.1.1",
"deepmerge": "^1.1.0",
"del": "^2.2.2",
"enzyme": "^3.2.0",
@@ -62,7 +65,7 @@
"gulp-sass": "^4.0.0",
"husky": "^0.14.3",
"jasmine-core": "^2.5.2",
- "jest": "^23.6.0",
+ "jest": "^24.8.0",
"jquery": "^3.2.1",
"js-beautify": "^1.7.5",
"json-loader": "^0.5.4",
@@ -95,8 +98,8 @@
"resize-observer-polyfill": "^1.5.0"
},
"peerDependencies": {
- "react": "^0.14.0 || ^15.0.1 || ^16.0.0",
- "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0"
+ "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0",
+ "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0"
},
"jest": {
"setupFiles": [
@@ -125,7 +128,7 @@
"bugs": {
"url": "https://github.com/akiran/react-slick/issues"
},
- "homepage": "https://github.com/akiran/react-slick",
+ "homepage": "https://react-slick.neostack.com",
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/react-slick",
diff --git a/src/default-props.js b/src/default-props.js
index 8d828ad..c98806a 100644
--- a/src/default-props.js
+++ b/src/default-props.js
@@ -1,6 +1,6 @@
import React from "react";
-var defaultProps = {
+let defaultProps = {
accessibility: true,
adaptiveHeight: false,
afterChange: null,
diff --git a/src/dots.js b/src/dots.js
index 908a391..93520cb 100644
--- a/src/dots.js
+++ b/src/dots.js
@@ -2,9 +2,10 @@
import React from "react";
import classnames from "classnames";
+import { clamp } from "./utils/innerSliderUtils";
-var getDotCount = function(spec) {
- var dots;
+const getDotCount = spec => {
+ let dots;
if (spec.infinite) {
dots = Math.ceil(spec.slideCount / spec.slidesToScroll);
@@ -25,47 +26,55 @@ export class Dots extends React.PureComponent {
this.props.clickHandler(options);
}
render() {
- var dotCount = getDotCount({
- slideCount: this.props.slideCount,
- slidesToScroll: this.props.slidesToScroll,
- slidesToShow: this.props.slidesToShow,
- infinite: this.props.infinite
+ const {
+ onMouseEnter,
+ onMouseOver,
+ onMouseLeave,
+ infinite,
+ slidesToScroll,
+ slidesToShow,
+ slideCount,
+ currentSlide
+ } = this.props;
+ let dotCount = getDotCount({
+ slideCount,
+ slidesToScroll,
+ slidesToShow,
+ infinite
});
- // Apply join & split to Array to pre-fill it for IE8
- //
- // Credit: http://stackoverflow.com/a/13735425/1849458
- const { onMouseEnter, onMouseOver, onMouseLeave } = this.props;
const mouseEvents = { onMouseEnter, onMouseOver, onMouseLeave };
- var dots = Array.apply(
- null,
- Array(dotCount + 1)
- .join("0")
- .split("")
- ).map((x, i) => {
- var leftBound = i * this.props.slidesToScroll;
- var rightBound =
- i * this.props.slidesToScroll + (this.props.slidesToScroll - 1);
- var className = classnames({
- "slick-active":
- this.props.currentSlide >= leftBound &&
- this.props.currentSlide <= rightBound
+ let dots = [];
+ for (let i = 0; i < dotCount; i++) {
+ let _rightBound = (i + 1) * slidesToScroll - 1;
+ let rightBound = infinite
+ ? _rightBound
+ : clamp(_rightBound, 0, slideCount - 1);
+ let _leftBound = rightBound - (slidesToScroll - 1);
+ let leftBound = infinite
+ ? _leftBound
+ : clamp(_leftBound, 0, slideCount - 1);
+
+ let className = classnames({
+ "slick-active": infinite
+ ? currentSlide >= leftBound && currentSlide <= rightBound
+ : currentSlide === leftBound
});
- var dotOptions = {
+ let dotOptions = {
message: "dots",
index: i,
- slidesToScroll: this.props.slidesToScroll,
- currentSlide: this.props.currentSlide
+ slidesToScroll,
+ currentSlide
};
- var onClick = this.clickHandler.bind(this, dotOptions);
- return (
+ let onClick = this.clickHandler.bind(this, dotOptions);
+ dots = dots.concat(
{React.cloneElement(this.props.customPaging(i), { onClick })}
);
- });
+ }
return React.cloneElement(this.props.appendDots(dots), {
className: this.props.dotsClass,
diff --git a/src/initial-state.js b/src/initial-state.js
index 4eaa983..5d5e157 100644
--- a/src/initial-state.js
+++ b/src/initial-state.js
@@ -20,7 +20,8 @@ const initialState = {
swiping: false,
touchObject: { startX: 0, startY: 0, curX: 0, curY: 0 },
trackStyle: {},
- trackWidth: 0
+ trackWidth: 0,
+ targetSlide: 0
};
export default initialState;
diff --git a/src/inner-slider.js b/src/inner-slider.js
index 4d267f7..96a39f4 100644
--- a/src/inner-slider.js
+++ b/src/inner-slider.js
@@ -1,7 +1,6 @@
"use strict";
import React from "react";
-import ReactDOM from "react-dom";
import initialState from "./initial-state";
import debounce from "lodash.debounce";
import classnames from "classnames";
@@ -10,6 +9,7 @@ import {
extractObject,
initializedState,
getHeight,
+ getWidth,
canGoNext,
slideHandler,
changeSlide,
@@ -36,11 +36,14 @@ export class InnerSlider extends React.Component {
this.state = {
...initialState,
currentSlide: this.props.initialSlide,
- slideCount: React.Children.count(this.props.children)
+ slideCount: React.Children.count(this.props.children),
+ slidesToShow: this.props.slidesToShow
};
this.callbackTimers = [];
this.clickable = true;
this.debouncedResize = null;
+ const ssrState = this.ssrInit();
+ this.state = { ...this.state, ...ssrState };
}
listRefHandler = ref => (this.list = ref);
trackRefHandler = ref => (this.track = ref);
@@ -52,8 +55,7 @@ export class InnerSlider extends React.Component {
this.list.style.height = getHeight(elem) + "px";
}
};
- componentWillMount = () => {
- this.ssrInit();
+ componentDidMount = () => {
this.props.onInit && this.props.onInit();
if (this.props.lazyLoad) {
let slidesToLoad = getOnDemandLazySlides({
@@ -69,8 +71,6 @@ export class InnerSlider extends React.Component {
}
}
}
- };
- componentDidMount = () => {
let spec = { listRef: this.list, trackRef: this.track, ...this.props };
this.updateState(spec, true, () => {
this.adaptHeight();
@@ -90,14 +90,6 @@ export class InnerSlider extends React.Component {
}
});
this.ro.observe(this.list);
- Array.prototype.forEach.call(
- document.querySelectorAll(".slick-slide"),
- slide => {
- slide.onfocus = this.props.pauseOnFocus ? this.onSlideFocus : null;
- slide.onblur = this.props.pauseOnFocus ? this.onSlideBlur : null;
- }
- );
-
if (this.props.touchMove) {
// swipeMove calls preventDefault which only has an effect on non-passive events
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
@@ -105,11 +97,14 @@ export class InnerSlider extends React.Component {
passive: false
});
}
-
- // To support server-side rendering
- if (!window) {
- return;
- }
+ document.querySelectorAll &&
+ Array.prototype.forEach.call(
+ document.querySelectorAll(".slick-slide"),
+ slide => {
+ slide.onfocus = this.props.pauseOnFocus ? this.onSlideFocus : null;
+ slide.onblur = this.props.pauseOnFocus ? this.onSlideBlur : null;
+ }
+ );
if (window.addEventListener) {
window.addEventListener("resize", this.onWindowResized);
} else {
@@ -143,47 +138,34 @@ export class InnerSlider extends React.Component {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer);
}
+ this.ro.disconnect();
};
- componentWillReceiveProps = nextProps => {
- let spec = {
- listRef: this.list,
- trackRef: this.track,
- ...nextProps,
- ...this.state
- };
+
+ didPropsChange(prevProps) {
let setTrackStyle = false;
for (let key of Object.keys(this.props)) {
- if (!nextProps.hasOwnProperty(key)) {
+ if (!prevProps.hasOwnProperty(key)) {
setTrackStyle = true;
break;
}
if (
- typeof nextProps[key] === "object" ||
- typeof nextProps[key] === "function"
+ typeof prevProps[key] === "object" ||
+ typeof prevProps[key] === "function"
) {
continue;
}
- if (nextProps[key] !== this.props[key]) {
+ if (prevProps[key] !== this.props[key]) {
setTrackStyle = true;
break;
}
}
- this.updateState(spec, setTrackStyle, () => {
- if (this.state.currentSlide >= React.Children.count(nextProps.children)) {
- this.changeSlide({
- message: "index",
- index:
- React.Children.count(nextProps.children) - nextProps.slidesToShow,
- currentSlide: this.state.currentSlide
- });
- }
- if (nextProps.autoplay) {
- this.autoPlay("update");
- } else {
- this.pause("paused");
- }
- });
- };
+ return (
+ setTrackStyle ||
+ React.Children.count(this.props.children) !==
+ React.Children.count(prevProps.children)
+ );
+ }
+
componentDidUpdate = prevProps => {
this.checkImagesLoad();
this.props.onReInit && this.props.onReInit();
@@ -214,14 +196,68 @@ export class InnerSlider extends React.Component {
passive: false
});
}
+ let spec = {
+ listRef: this.list,
+ trackRef: this.track,
+ ...this.props,
+ ...this.state
+ };
+ const setTrackStyle = this.didPropsChange(prevProps);
+ setTrackStyle &&
+ this.updateState(spec, setTrackStyle, () => {
+ if (
+ this.state.currentSlide >= React.Children.count(this.props.children)
+ ) {
+ this.changeSlide({
+ message: "index",
+ index:
+ React.Children.count(this.props.children) -
+ this.props.slidesToShow,
+ currentSlide: this.state.currentSlide
+ });
+ }
+ if (this.props.autoplay) {
+ this.autoPlay("update");
+ } else {
+ this.pause("paused");
+ }
+ });
};
onWindowResized = setTrackStyle => {
if (this.debouncedResize) this.debouncedResize.cancel();
this.debouncedResize = debounce(() => this.resizeWindow(setTrackStyle), 50);
this.debouncedResize();
};
+ calcRealSlideShowed = () => {
+ var realSlideShowed = 0;
+ if (!this.props.infinite && this.props.variableWidth) {
+ let widthUntilListRightEnd = 0;
+ var trackElem = ReactDOM.findDOMNode(this.track);
+ var listWidth = Math.ceil(getWidth(ReactDOM.findDOMNode(this.list)));
+ for (
+ let slide = this.state.currentSlide;
+ slide < trackElem.childNodes.length;
+ slide++
+ ) {
+ widthUntilListRightEnd +=
+ trackElem &&
+ trackElem.children[slide] &&
+ trackElem.children[slide].offsetWidth;
+
+ if (widthUntilListRightEnd >= listWidth) {
+ realSlideShowed = slide - 2;
+ break;
+ }
+ }
+ }
+ this.setState({
+ slidesToShow: realSlideShowed || this.props.slidesToShow
+ });
+ };
resizeWindow = (setTrackStyle = true) => {
- if (!ReactDOM.findDOMNode(this.track)) return;
+ const isTrackMounted = Boolean(this.track && this.track.node);
+ // prevent warning: setting state on unmounted component (server side rendering)
+ if (!isTrackMounted) return;
let spec = {
listRef: this.list,
trackRef: this.track,
@@ -292,10 +328,9 @@ export class InnerSlider extends React.Component {
let currentWidth = `${childrenWidths[this.state.currentSlide]}px`;
trackStyle.left = `calc(${trackStyle.left} + (100% - ${currentWidth}) / 2 ) `;
}
- this.setState({
+ return {
trackStyle
- });
- return;
+ };
}
let childrenCount = React.Children.count(this.props.children);
const spec = { ...this.props, ...this.state, slideCount: childrenCount };
@@ -314,13 +349,17 @@ export class InnerSlider extends React.Component {
width: trackWidth + "%",
left: trackLeft + "%"
};
- this.setState({
+ return {
slideWidth: slideWidth + "%",
trackStyle: trackStyle
- });
+ };
};
checkImagesLoad = () => {
- let images = document.querySelectorAll(".slick-slide img");
+ let images =
+ (this.list &&
+ this.list.querySelectorAll &&
+ this.list.querySelectorAll(".slick-slide img")) ||
+ [];
let imagesCount = images.length,
loadedCount = 0;
Array.prototype.forEach.call(images, image => {
@@ -413,10 +452,17 @@ export class InnerSlider extends React.Component {
value => this.state.lazyLoadedList.indexOf(value) < 0
);
onLazyLoad && slidesToLoad.length > 0 && onLazyLoad(slidesToLoad);
+ if (!this.props.waitForAnimate && this.animationEndCallback) {
+ clearTimeout(this.animationEndCallback);
+ afterChange && afterChange(currentSlide);
+ delete this.animationEndCallback;
+ }
this.setState(state, () => {
- asNavFor &&
- asNavFor.innerSlider.state.currentSlide !== currentSlide &&
+ // asNavForIndex check is to avoid recursive calls of slideHandler in waitForAnimate=false mode
+ if (asNavFor && this.asNavForIndex !== index) {
+ this.asNavForIndex = index;
asNavFor.innerSlider.slideHandler(index);
+ }
if (!nextState) return;
this.animationEndCallback = setTimeout(() => {
this.clickable = true;
@@ -440,6 +486,11 @@ export class InnerSlider extends React.Component {
} else {
this.slideHandler(targetSlide);
}
+ this.props.autoplay && this.autoPlay("update");
+ if (this.props.focusOnSelect) {
+ const nodes = this.list.querySelectorAll(".slick-current");
+ nodes[0] && nodes[0].focus();
+ }
};
clickHandler = e => {
if (this.clickable === false) {
@@ -508,6 +559,10 @@ export class InnerSlider extends React.Component {
this.enableBodyScroll();
}
};
+ touchEnd = e => {
+ this.swipeEnd(e);
+ this.clickable = true;
+ };
slickPrev = () => {
// this and fellow methods are wrapped in setTimeout
// to make sure initialize setState has happened before
@@ -641,7 +696,9 @@ export class InnerSlider extends React.Component {
"trackStyle",
"variableWidth",
"unslick",
- "centerPadding"
+ "centerPadding",
+ "targetSlide",
+ "useCSS"
]);
const { pauseOnHover } = this.props;
trackProps = {
@@ -649,7 +706,8 @@ export class InnerSlider extends React.Component {
onMouseEnter: pauseOnHover ? this.onTrackOver : null,
onMouseLeave: pauseOnHover ? this.onTrackLeave : null,
onMouseOver: pauseOnHover ? this.onTrackOver : null,
- focusOnSelect: this.props.focusOnSelect ? this.selectHandler : null
+ focusOnSelect:
+ this.props.focusOnSelect && this.clickable ? this.selectHandler : null
};
var dots;
@@ -732,14 +790,16 @@ export class InnerSlider extends React.Component {
onMouseUp: touchMove ? this.swipeEnd : null,
onMouseLeave: this.state.dragging && touchMove ? this.swipeEnd : null,
onTouchStart: touchMove ? this.swipeStart : null,
- onTouchEnd: touchMove ? this.swipeEnd : null,
+ onTouchMove: this.state.dragging && touchMove ? this.swipeMove : null,
+ onTouchEnd: touchMove ? this.touchEnd : null,
onTouchCancel: this.state.dragging && touchMove ? this.swipeEnd : null,
onKeyDown: this.props.accessibility ? this.keyHandler : null
};
let innerSliderProps = {
className: className,
- dir: "ltr"
+ dir: "ltr",
+ style: this.props.style
};
if (this.props.unslick) {
diff --git a/src/slider.js b/src/slider.js
index d4833da..65d63a4 100644
--- a/src/slider.js
+++ b/src/slider.js
@@ -25,7 +25,7 @@ export default class Slider extends React.Component {
}
// handles responsive breakpoints
- componentWillMount() {
+ componentDidMount() {
// performance monitoring
//if (process.env.NODE_ENV !== 'production') {
//const { whyDidYouUpdate } = require('why-did-you-update')
@@ -106,9 +106,7 @@ export default class Slider extends React.Component {
process.env.NODE_ENV !== "production"
) {
console.warn(
- `slidesToScroll should be equal to 1 in centerMode, you are using ${
- settings.slidesToScroll
- }`
+ `slidesToScroll should be equal to 1 in centerMode, you are using ${settings.slidesToScroll}`
);
}
settings.slidesToScroll = 1;
@@ -117,9 +115,7 @@ export default class Slider extends React.Component {
if (settings.fade) {
if (settings.slidesToShow > 1 && process.env.NODE_ENV !== "production") {
console.warn(
- `slidesToShow should be equal to 1 when fade is true, you're using ${
- settings.slidesToShow
- }`
+ `slidesToShow should be equal to 1 when fade is true, you're using ${settings.slidesToShow}`
);
}
if (
@@ -127,9 +123,7 @@ export default class Slider extends React.Component {
process.env.NODE_ENV !== "production"
) {
console.warn(
- `slidesToScroll should be equal to 1 when fade is true, you're using ${
- settings.slidesToScroll
- }`
+ `slidesToScroll should be equal to 1 when fade is true, you're using ${settings.slidesToScroll}`
);
}
settings.slidesToShow = 1;
@@ -203,12 +197,16 @@ export default class Slider extends React.Component {
if (settings === "unslick") {
const className = "regular slider " + (this.props.className || "");
- return
{newChildren}
;
+ return
{children}
;
} else if (newChildren.length <= settings.slidesToShow) {
settings.unslick = true;
}
return (
-
+
{newChildren}
);
diff --git a/src/track.js b/src/track.js
index 4b4bd31..f8924c8 100644
--- a/src/track.js
+++ b/src/track.js
@@ -9,9 +9,9 @@ import {
} from "./utils/innerSliderUtils";
// given specifications/props for a slide, fetch all the classes that need to be applied to the slide
-var getSlideClasses = spec => {
- var slickActive, slickCenter, slickCloned;
- var centerOffset, index;
+const getSlideClasses = spec => {
+ let slickActive, slickCenter, slickCloned;
+ let centerOffset, index;
if (spec.rtl) {
index = spec.slideCount - 1 - spec.index;
@@ -33,7 +33,16 @@ var getSlideClasses = spec => {
spec.currentSlide <= index &&
index < spec.currentSlide + spec.slidesToShow;
}
- let slickCurrent = index === spec.currentSlide;
+
+ let focusedSlide;
+ if (spec.targetSlide < 0) {
+ focusedSlide = spec.targetSlide + spec.slideCount;
+ } else if (spec.targetSlide >= spec.slideCount) {
+ focusedSlide = spec.targetSlide - spec.slideCount;
+ } else {
+ focusedSlide = spec.targetSlide;
+ }
+ let slickCurrent = index === focusedSlide;
return {
"slick-slide": true,
"slick-active": slickActive,
@@ -43,8 +52,8 @@ var getSlideClasses = spec => {
};
};
-var getSlideStyle = function(spec) {
- var style = {};
+const getSlideStyle = spec => {
+ let style = {};
if (spec.variableWidth === undefined || spec.variableWidth === false) {
style.width = spec.slideWidth;
@@ -58,26 +67,18 @@ var getSlideStyle = function(spec) {
style.left = -spec.index * parseInt(spec.slideWidth);
}
style.opacity = spec.currentSlide === spec.index ? 1 : 0;
- style.transition =
- "opacity " +
- spec.speed +
- "ms " +
- spec.cssEase +
- ", " +
- "visibility " +
- spec.speed +
- "ms " +
- spec.cssEase;
- style.WebkitTransition =
- "opacity " +
- spec.speed +
- "ms " +
- spec.cssEase +
- ", " +
- "visibility " +
- spec.speed +
- "ms " +
- spec.cssEase;
+ if (spec.useCSS) {
+ style.transition =
+ "opacity " +
+ spec.speed +
+ "ms " +
+ spec.cssEase +
+ ", " +
+ "visibility " +
+ spec.speed +
+ "ms " +
+ spec.cssEase;
+ }
}
return style;
@@ -85,18 +86,18 @@ var getSlideStyle = function(spec) {
const getKey = (child, fallbackKey) => child.key || fallbackKey;
-var renderSlides = function(spec) {
- var key;
- var slides = [];
- var preCloneSlides = [];
- var postCloneSlides = [];
- var childrenCount = React.Children.count(spec.children);
+const renderSlides = spec => {
+ let key;
+ let slides = [];
+ let preCloneSlides = [];
+ let postCloneSlides = [];
+ let childrenCount = React.Children.count(spec.children);
let startIndex = lazyStartIndex(spec);
let endIndex = lazyEndIndex(spec);
React.Children.forEach(spec.children, (elem, index) => {
let child;
- var childOnClickOptions = {
+ let childOnClickOptions = {
message: "children",
index: index,
slidesToScroll: spec.slidesToScroll,
@@ -112,8 +113,8 @@ var renderSlides = function(spec) {
} else {
child = ;
}
- var childStyle = getSlideStyle({ ...spec, index });
- const slideClass = child.props.className || "";
+ let childStyle = getSlideStyle({ ...spec, index });
+ let slideClass = child.props.className || "";
let slideClasses = getSlideClasses({ ...spec, index });
// push a cloned element of the desired slide
slides.push(
@@ -197,12 +198,19 @@ var renderSlides = function(spec) {
};
export class Track extends React.PureComponent {
+ node = null;
+
+ handleRef = ref => {
+ this.node = ref;
+ };
+
render() {
const slides = renderSlides(this.props);
const { onMouseEnter, onMouseOver, onMouseLeave } = this.props;
const mouseEvents = { onMouseEnter, onMouseOver, onMouseLeave };
return (
{
+ const passiveEvents = ["onTouchStart", "onTouchMove", "onWheel"];
+ if (!passiveEvents.includes(event._reactName)) {
+ event.preventDefault();
+ }
+};
export const getOnDemandLazySlides = spec => {
let onDemandSlides = [];
@@ -24,19 +34,25 @@ export const getRequiredLazySlides = spec => {
return requiredSlides;
};
-const getPreloadNumber = (lazyLoad) => {
- const [preloadBefore = 0, preloadAfter = 0] = Array.isArray(lazyLoad) ? lazyLoad : [0, 0];
+const getPreloadNumber = lazyLoad => {
+ const [preloadBefore = 0, preloadAfter = 0] = Array.isArray(lazyLoad)
+ ? lazyLoad
+ : [0, 0];
return {
preloadBefore: parseInt(preloadBefore, 10),
preloadAfter: parseInt(preloadAfter, 10)
- }
-}
+ };
+};
// startIndex that needs to be present
export const lazyStartIndex = spec =>
- spec.currentSlide - lazySlidesOnLeft(spec) - getPreloadNumber(spec.lazyLoad).preloadBefore;
+ spec.currentSlide -
+ lazySlidesOnLeft(spec) -
+ getPreloadNumber(spec.lazyLoad).preloadBefore;
export const lazyEndIndex = spec =>
- spec.currentSlide + lazySlidesOnRight(spec) + getPreloadNumber(spec.lazyLoad).preloadAfter;
+ spec.currentSlide +
+ lazySlidesOnRight(spec) +
+ getPreloadNumber(spec.lazyLoad).preloadAfter;
export const lazySlidesOnLeft = spec =>
spec.centerMode
@@ -58,7 +74,7 @@ export const getSwipeDirection = (touchObject, verticalSwiping = false) => {
xDist = touchObject.startX - touchObject.curX;
yDist = touchObject.startY - touchObject.curY;
r = Math.atan2(yDist, xDist);
- swipeAngle = Math.round(r * 180 / Math.PI);
+ swipeAngle = Math.round((r * 180) / Math.PI);
if (swipeAngle < 0) {
swipeAngle = 360 - Math.abs(swipeAngle);
}
@@ -109,8 +125,10 @@ export const extractObject = (spec, keys) => {
export const initializedState = spec => {
// spec also contains listRef, trackRef
let slideCount = React.Children.count(spec.children);
- let listWidth = Math.ceil(getWidth(ReactDOM.findDOMNode(spec.listRef)));
- let trackWidth = Math.ceil(getWidth(ReactDOM.findDOMNode(spec.trackRef)));
+ const listNode = spec.listRef;
+ let listWidth = Math.ceil(getWidth(listNode));
+ const trackNode = spec.trackRef && spec.trackRef.node;
+ let trackWidth = Math.ceil(getWidth(trackNode));
let slideWidth;
if (!spec.vertical) {
let centerPaddingAdj = spec.centerMode && parseInt(spec.centerPadding) * 2;
@@ -125,10 +143,7 @@ export const initializedState = spec => {
slideWidth = listWidth;
}
let slideHeight =
- ReactDOM.findDOMNode(spec.listRef) &&
- getHeight(
- ReactDOM.findDOMNode(spec.listRef).querySelector('[data-index="0"]')
- );
+ listNode && getHeight(listNode.querySelector('[data-index="0"]'));
let listHeight = slideHeight * spec.slidesToShow;
let currentSlide =
spec.currentSlide === undefined ? spec.initialSlide : spec.currentSlide;
@@ -136,11 +151,12 @@ export const initializedState = spec => {
currentSlide = slideCount - 1 - spec.initialSlide;
}
let lazyLoadedList = spec.lazyLoadedList || [];
- let slidesToLoad = getOnDemandLazySlides(
- { currentSlide, lazyLoadedList },
- spec
- );
- lazyLoadedList.concat(slidesToLoad);
+ let slidesToLoad = getOnDemandLazySlides({
+ ...spec,
+ currentSlide,
+ lazyLoadedList
+ });
+ lazyLoadedList = lazyLoadedList.concat(slidesToLoad);
let state = {
slideCount,
@@ -168,7 +184,6 @@ export const slideHandler = spec => {
infinite,
index,
slideCount,
- lazyLoadedList,
lazyLoad,
currentSlide,
centerMode,
@@ -176,6 +191,7 @@ export const slideHandler = spec => {
slidesToShow,
useCSS
} = spec;
+ let { lazyLoadedList } = spec;
if (waitForAnimate && animating) return {};
let animationSlide = index,
finalSlide,
@@ -183,6 +199,7 @@ export const slideHandler = spec => {
finalLeft;
let state = {},
nextState = {};
+ const targetSlide = infinite ? index : clamp(index, 0, slideCount - 1);
if (fade) {
if (!infinite && (index < 0 || index >= slideCount)) return {};
if (index < 0) {
@@ -191,21 +208,22 @@ export const slideHandler = spec => {
animationSlide = index - slideCount;
}
if (lazyLoad && lazyLoadedList.indexOf(animationSlide) < 0) {
- lazyLoadedList.push(animationSlide);
+ lazyLoadedList = lazyLoadedList.concat(animationSlide);
}
state = {
animating: true,
currentSlide: animationSlide,
- lazyLoadedList
+ lazyLoadedList,
+ targetSlide: animationSlide
};
- nextState = { animating: false };
+ nextState = { animating: false, targetSlide: animationSlide };
} else {
finalSlide = animationSlide;
if (animationSlide < 0) {
finalSlide = animationSlide + slideCount;
if (!infinite) finalSlide = 0;
else if (slideCount % slidesToScroll !== 0)
- finalSlide = slideCount - slideCount % slidesToScroll;
+ finalSlide = slideCount - (slideCount % slidesToScroll);
} else if (!canGoNext(spec) && animationSlide > currentSlide) {
animationSlide = finalSlide = currentSlide;
} else if (centerMode && animationSlide >= slideCount) {
@@ -216,34 +234,43 @@ export const slideHandler = spec => {
if (!infinite) finalSlide = slideCount - slidesToShow;
else if (slideCount % slidesToScroll !== 0) finalSlide = 0;
}
+
+ if (!infinite && animationSlide + slidesToShow >= slideCount) {
+ finalSlide = slideCount - slidesToShow;
+ }
+
animationLeft = getTrackLeft({ ...spec, slideIndex: animationSlide });
finalLeft = getTrackLeft({ ...spec, slideIndex: finalSlide });
if (!infinite) {
if (animationLeft === finalLeft) animationSlide = finalSlide;
animationLeft = finalLeft;
}
- lazyLoad &&
- lazyLoadedList.concat(
+ if (lazyLoad) {
+ lazyLoadedList = lazyLoadedList.concat(
getOnDemandLazySlides({ ...spec, currentSlide: animationSlide })
);
+ }
if (!useCSS) {
state = {
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
- lazyLoadedList
+ lazyLoadedList,
+ targetSlide
};
} else {
state = {
animating: true,
currentSlide: finalSlide,
trackStyle: getTrackAnimateCSS({ ...spec, left: animationLeft }),
- lazyLoadedList
+ lazyLoadedList,
+ targetSlide
};
nextState = {
animating: false,
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
- swipeLeft: null
+ swipeLeft: null,
+ targetSlide
};
}
}
@@ -257,12 +284,12 @@ export const changeSlide = (spec, options) => {
slidesToShow,
slideCount,
currentSlide,
+ targetSlide: previousTargetSlide,
lazyLoad,
infinite
} = spec;
unevenOffset = slideCount % slidesToScroll !== 0;
indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;
-
if (options.message === "previous") {
slideOffset =
indexOffset === 0 ? slidesToScroll : slidesToShow - indexOffset;
@@ -271,24 +298,25 @@ export const changeSlide = (spec, options) => {
previousInt = currentSlide - slideOffset;
targetSlide = previousInt === -1 ? slideCount - 1 : previousInt;
}
+ if (!infinite) {
+ targetSlide = previousTargetSlide - slidesToScroll;
+ }
} else if (options.message === "next") {
slideOffset = indexOffset === 0 ? slidesToScroll : indexOffset;
targetSlide = currentSlide + slideOffset;
if (lazyLoad && !infinite) {
- targetSlide = (currentSlide + slidesToScroll) % slideCount + indexOffset;
+ targetSlide =
+ ((currentSlide + slidesToScroll) % slideCount) + indexOffset;
+ }
+ if (!infinite) {
+ targetSlide = previousTargetSlide + slidesToScroll;
}
} else if (options.message === "dots") {
// Click on dots
targetSlide = options.index * options.slidesToScroll;
- if (targetSlide === options.currentSlide) {
- return null;
- }
} else if (options.message === "children") {
// Click on the slides
targetSlide = options.index;
- if (targetSlide === options.currentSlide) {
- return null;
- }
if (infinite) {
let direction = siblingDirection({ ...spec, targetSlide });
if (targetSlide > options.currentSlide && direction === "left") {
@@ -299,9 +327,6 @@ export const changeSlide = (spec, options) => {
}
} else if (options.message === "index") {
targetSlide = Number(options.index);
- if (targetSlide === options.currentSlide) {
- return null;
- }
}
return targetSlide;
};
@@ -314,7 +339,7 @@ export const keyHandler = (e, accessibility, rtl) => {
};
export const swipeStart = (e, swipe, draggable) => {
- e.target.tagName === "IMG" && e.preventDefault();
+ e.target.tagName === "IMG" && safePreventDefault(e);
if (!swipe || (!draggable && e.type.indexOf("mouse") !== -1)) return "";
return {
dragging: true,
@@ -351,8 +376,8 @@ export const swipeMove = (e, spec) => {
listWidth
} = spec;
if (scrolling || !dragging) return;
- if (animating) return e.preventDefault();
- if (vertical && swipeToSlide && verticalSwiping) e.preventDefault();
+ if (animating) return safePreventDefault(e);
+ if (vertical && swipeToSlide && verticalSwiping) safePreventDefault(e);
let swipeLeft,
state = {};
let curLeft = getTrackLeft(spec);
@@ -378,9 +403,12 @@ export const swipeMove = (e, spec) => {
let touchSwipeLength = touchObject.swipeLength;
if (!infinite) {
if (
- (currentSlide === 0 && swipeDirection === "right") ||
- (currentSlide + 1 >= dotCount && swipeDirection === "left") ||
- (!canGoNext(spec) && swipeDirection === "left")
+ (currentSlide === 0 &&
+ (swipeDirection === "right" || swipeDirection === "down")) ||
+ (currentSlide + 1 >= dotCount &&
+ (swipeDirection === "left" || swipeDirection === "up")) ||
+ (!canGoNext(spec) &&
+ (swipeDirection === "left" || swipeDirection === "up"))
) {
touchSwipeLength = touchObject.swipeLength * edgeFriction;
if (edgeDragged === false && onEdge) {
@@ -420,7 +448,7 @@ export const swipeMove = (e, spec) => {
}
if (touchObject.swipeLength > 10) {
state["swiping"] = true;
- e.preventDefault();
+ safePreventDefault(e);
}
return state;
};
@@ -433,13 +461,15 @@ export const swipeEnd = (e, spec) => {
touchThreshold,
verticalSwiping,
listHeight,
- currentSlide,
swipeToSlide,
scrolling,
- onSwipe
+ onSwipe,
+ targetSlide,
+ currentSlide,
+ infinite
} = spec;
if (!dragging) {
- if (swipe) e.preventDefault();
+ if (swipe) safePreventDefault(e);
return {};
}
let minSwipe = verticalSwiping
@@ -463,26 +493,27 @@ export const swipeEnd = (e, spec) => {
return state;
}
if (touchObject.swipeLength > minSwipe) {
- e.preventDefault();
+ safePreventDefault(e);
if (onSwipe) {
onSwipe(swipeDirection);
}
let slideCount, newSlide;
+ let activeSlide = infinite ? currentSlide : targetSlide;
switch (swipeDirection) {
case "left":
case "up":
- newSlide = currentSlide + getSlideCount(spec);
+ newSlide = activeSlide + getSlideCount(spec);
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide;
state["currentDirection"] = 0;
break;
case "right":
case "down":
- newSlide = currentSlide - getSlideCount(spec);
+ newSlide = activeSlide - getSlideCount(spec);
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide;
state["currentDirection"] = 1;
break;
default:
- slideCount = currentSlide;
+ slideCount = activeSlide;
}
state["triggerSlideHandler"] = slideCount;
} else {
@@ -526,8 +557,11 @@ export const getSlideCount = spec => {
: 0;
if (spec.swipeToSlide) {
let swipedSlide;
- const slickList = ReactDOM.findDOMNode(spec.listRef);
- const slides = slickList.querySelectorAll(".slick-slide");
+ const slickList = spec.listRef;
+ const slides =
+ (slickList.querySelectorAll &&
+ slickList.querySelectorAll(".slick-slide")) ||
+ [];
Array.from(slides).every(slide => {
if (!spec.vertical) {
if (
@@ -578,7 +612,14 @@ export const getTrackCSS = spec => {
let trackWidth, trackHeight;
const trackChildren = spec.slideCount + 2 * spec.slidesToShow;
if (!spec.vertical) {
- trackWidth = getTotalSlides(spec) * spec.slideWidth;
+ if (spec.variableWidth) {
+ trackWidth = 0;
+ spec.children.forEach(function(child) {
+ trackWidth += child.props.style.width;
+ });
+ } else {
+ trackWidth = getTotalSlides(spec) * spec.slideWidth;
+ }
} else {
trackHeight = trackChildren * spec.slideHeight;
}
@@ -715,7 +756,7 @@ export const getTrackLeft = spec => {
slideCount % slidesToScroll !== 0 &&
slideIndex + slidesToScroll > slideCount
) {
- slidesToOffset = slidesToShow - slideCount % slidesToScroll;
+ slidesToOffset = slidesToShow - (slideCount % slidesToScroll);
}
if (centerMode) {
slidesToOffset = parseInt(slidesToShow / 2);
@@ -732,10 +773,29 @@ export const getTrackLeft = spec => {
if (variableWidth === true) {
var targetSlideIndex;
- let trackElem = ReactDOM.findDOMNode(trackRef);
+ const trackElem = trackRef && trackRef.node;
targetSlideIndex = slideIndex + getPreClones(spec);
targetSlide = trackElem && trackElem.childNodes[targetSlideIndex];
targetLeft = targetSlide ? targetSlide.offsetLeft * -1 : 0;
+ if (!infinite) {
+ let widthUntilListRightEnd = 0;
+ for (
+ let slide = targetSlideIndex;
+ slide < trackElem.childNodes.length;
+ slide++
+ ) {
+ widthUntilListRightEnd +=
+ trackElem &&
+ trackElem.children[slide] &&
+ trackElem.children[slide].offsetWidth;
+ }
+ if (widthUntilListRightEnd < listWidth) {
+ targetLeft += listWidth - widthUntilListRightEnd;
+ if (targetLeft >= 0) {
+ targetLeft = 0;
+ }
+ }
+ }
if (centerMode === true) {
targetSlideIndex = infinite
? slideIndex + getPreClones(spec)
diff --git a/webpack.config.js b/webpack.config.js
index 407721c..e4e96d4 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -5,7 +5,7 @@ module.exports = {
mode: "production",
devtool: "source-map",
entry: {
- "docs.js": "./docs/index.jsx"
+ "docs.js": "./docs/index.js"
},
output: {
path: path.join(__dirname, "build"),