├── .travis.yml
├── src
├── index.js
├── initial-state.js
├── default-props.js
├── dots.js
├── arrows.js
├── slider.js
├── track.js
├── mixins
│ ├── trackHelper.js
│ ├── event-handlers.js
│ └── helpers.js
└── inner-slider.js
├── CONTRIBUTING.markdown
├── docs
├── img
│ └── react-slick
│ │ ├── abstract01.jpg
│ │ ├── abstract02.jpg
│ │ ├── abstract03.jpg
│ │ └── abstract04.jpg
├── index.jsx
├── docs.scss
├── routes.jsx
├── docs.jsx
├── index.html
├── _style.scss
└── demos.jsx
├── .babelrc
├── .gitignore
├── examples
├── config.js
├── SimpleSlider.js
├── UnevenSetsFinite.js
├── UnevenSetsInfinite.js
├── AutoPlay.js
├── Rtl.js
├── PauseOnHover.js
├── Fade.js
├── FocusOnSelect.js
├── MultipleItems.js
├── LazyLoad.js
├── CenterMode.js
├── VariableWidth.js
├── CustomSlides.js
├── CustomPaging.js
├── SwipeToSlide.js
├── SlideChangeHooks.js
├── VerticalMode.js
├── AdaptiveHeight.js
├── VerticalSwipeToSlide.js
├── DynamicSlides.js
├── SlickGoTo.js
├── PreviousNextMethods.js
├── CustomArrows.js
└── Responsive.js
├── ISSUE_TEMPLATE.md
├── test-setup.js
├── .npmignore
├── __tests__
├── index.js
├── sample.js
└── arrows.js
├── .jshintrc
├── .eslintrc
├── bower.json
├── webpack.config.dist.js
├── LICENSE
├── webpack.config.js
├── package.json
├── gulpfile.js
└── README.md
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "stable"
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./slider');
2 |
--------------------------------------------------------------------------------
/CONTRIBUTING.markdown:
--------------------------------------------------------------------------------
1 | Submitting Pull Requests
2 |
3 | * Make sure auto generated files like dist and lib are not part of PR
--------------------------------------------------------------------------------
/docs/img/react-slick/abstract01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eligolding/react-slick/master/docs/img/react-slick/abstract01.jpg
--------------------------------------------------------------------------------
/docs/img/react-slick/abstract02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eligolding/react-slick/master/docs/img/react-slick/abstract02.jpg
--------------------------------------------------------------------------------
/docs/img/react-slick/abstract03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eligolding/react-slick/master/docs/img/react-slick/abstract03.jpg
--------------------------------------------------------------------------------
/docs/img/react-slick/abstract04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eligolding/react-slick/master/docs/img/react-slick/abstract04.jpg
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets":[
3 | "react",
4 | ["es2015", {"loose": true}]
5 | ],
6 | "plugins": ["transform-object-assign", "transform-object-rest-spread"]
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bower_components
3 | .sass-cache
4 | build
5 | demos/*
6 | demos1
7 | TODO.md
8 | npm-debug.log
9 | lib
10 | *.sublime-*
11 | .idea
12 | dist
--------------------------------------------------------------------------------
/examples/config.js:
--------------------------------------------------------------------------------
1 |
2 | export const baseUrl = (process.env.NODE_ENV === 'production') ? 'https://s3.amazonaws.com/static.neostack.com/img/react-slick' : '/img/react-slick'
3 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Guidlines for posting new issue
2 |
3 | * Please replicate your issue with this [jsfiddle](https://jsfiddle.net/kirana/20bumb4g/) and provide a link to it along with the issue description
--------------------------------------------------------------------------------
/test-setup.js:
--------------------------------------------------------------------------------
1 | window.matchMedia = window.matchMedia || function() {
2 | return {
3 | matches : false,
4 | addListener : function() {},
5 | removeListener: function() {}
6 | };
7 | };
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | .sass-cache
3 | build
4 | demos
5 | demos1
6 | TODO.md
7 | test
8 | testlib
9 | bower.json
10 | gulpfile.js
11 | karma.conf.js
12 | LICENSE
13 | webpack.config.dist.js
14 | webpack.config.js
15 | ISSUE_TEMPLATE.md
16 |
--------------------------------------------------------------------------------
/docs/index.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react'
4 | import ReactDOM from 'react-dom'
5 | import Docs from './docs'
6 |
7 | React.initializeTouchEvents && React.initializeTouchEvents(true);
8 | ReactDOM.render(, document.getElementById('rapp'));
9 |
--------------------------------------------------------------------------------
/docs/docs.scss:
--------------------------------------------------------------------------------
1 |
2 | @import "foundation-apps/scss/foundation.scss";
3 | $primary-color: #00558B;
4 |
5 | $slick-font-path: "/fonts/";
6 | $slick-arrow-color: $primary-color;
7 |
8 | @import "slick-carousel/slick/slick.scss";
9 | @import "slick-carousel/slick/slick-theme.scss";
10 | @import "./style.scss";
11 |
--------------------------------------------------------------------------------
/__tests__/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import {shallow, mount} from 'enzyme';
5 | import Slider from '../src/index';
6 |
7 | describe('Slider', function() {
8 | it('should render', function() {
9 | const wrapper = shallow(slide1
);
10 | expect(wrapper.contains(
slide1
)).toBe(true);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true,
3 | "strict": true,
4 | "globalstrict": true,
5 | "node": true,
6 | "mocha": true,
7 | "browser": true,
8 | "bitwise": true,
9 | "camelcase": true,
10 | "curly": true,
11 | "eqeqeq": true,
12 | "immed": true,
13 | "indent": 2,
14 | "latedef": true,
15 | "newcap": true,
16 | "noarg": true,
17 | "undef": true,
18 | "unused": true
19 | }
--------------------------------------------------------------------------------
/docs/routes.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 | var Router = require('react-router');
5 | var Route = Router.Route;
6 | var Docs = require('./docs');
7 |
8 | var path = (process.env.NODE_ENV === 'dev_docs') ? '/': '/opensource/react-slick';
9 | var routes = (
10 |
11 |
12 | );
13 |
14 | module.exports = routes;
15 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-extra-parens": 0,
4 | "react/jsx-uses-vars": 1,
5 | "strict": 0,
6 | "quotes": [2, "single"],
7 | "no-underscore-dangle": 0,
8 | "space-infix-ops": 0,
9 | "no-alert": 0
10 | },
11 | "ecmaFeatures": {
12 | "jsx": true,
13 | },
14 | "env": {
15 | "node": true,
16 | "browser": true,
17 | "es6": true,
18 | "jasmine": true
19 | },
20 | "parser": "babel-eslint",
21 | "plugins": [
22 | "react"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/docs/docs.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react'
4 | import Demos from './demos'
5 |
6 | export default class Docs extends React.Component {
7 | render() {
8 | return (
9 |
10 |
11 | React Slick
12 |
13 |
18 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/__tests__/sample.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import React from 'react';
3 | import {shallow, mount} from 'enzyme';
4 | import Slider from '../src/index';
5 |
6 |
7 |
8 | describe('basic test', function() {
9 | it('should add numbers', function() {
10 | expect(2 + 2).toBe(4);
11 | });
12 | });
13 |
14 | describe('sample enzyme test', function() {
15 | it('should render', function() {
16 | const wrapper = shallow(slide1
);
17 | expect(wrapper.contains(slide1
)).toBe(true);
18 | });
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-slick",
3 | "main": "dist/react-slick.min.js",
4 | "version": "0.14.2",
5 | "homepage": "https://github.com/akiran/react-slick",
6 | "authors": [
7 | "Kiran Abburi"
8 | ],
9 | "license": "MIT",
10 | "ignore": [
11 | "**/.*",
12 | "node_modules",
13 | "bower_components",
14 | "test",
15 | "tests"
16 | ],
17 | "dependencies": {
18 | "slick-carousel": "~1.6.0"
19 | },
20 | "devDependencies": {
21 | "react": "~0.12.1",
22 | "jquery": "~2.1.1",
23 | "should": "~4.3.0",
24 | "foundation-apps": "~1.0.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/SimpleSlider.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class SimpleSlider extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | speed: 500,
10 | slidesToShow: 1,
11 | slidesToScroll: 1,
12 | };
13 | return (
14 |
15 |
Single Item
16 |
17 | 1
18 | 2
19 | 3
20 | 4
21 | 5
22 | 6
23 |
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/examples/UnevenSetsFinite.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class UnevenSetsFinite extends Component {
5 | render() {
6 | var settings = {
7 | dots: true,
8 | infinite: false,
9 | speed: 500,
10 | slidesToScroll: 4,
11 | slidesToShow: 4
12 | };
13 | return (
14 |
15 |
Uneven sets (finite)
16 |
17 | 1
18 | 2
19 | 3
20 | 4
21 | 5
22 | 6
23 |
24 |
25 | );
26 | }
27 | }
--------------------------------------------------------------------------------
/examples/UnevenSetsInfinite.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class UnevenSetsInfinite extends Component {
5 | render() {
6 | var settings = {
7 | dots: true,
8 | infinite: true,
9 | speed: 500,
10 | slidesToScroll: 4,
11 | slidesToShow: 4
12 | };
13 | return (
14 |
15 |
Uneven sets (infinite)
16 |
17 | 1
18 | 2
19 | 3
20 | 4
21 | 5
22 | 6
23 |
24 |
25 | );
26 | }
27 | }
--------------------------------------------------------------------------------
/examples/AutoPlay.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class AutoPlay extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | slidesToShow: 3,
10 | slidesToScroll: 1,
11 | autoplay: true,
12 | autoplaySpeed: 2000
13 | };
14 | return (
15 |
16 |
Auto Play
17 |
18 | 1
19 | 2
20 | 3
21 | 4
22 | 5
23 | 6
24 |
25 |
26 | );
27 | }
28 | }
--------------------------------------------------------------------------------
/examples/Rtl.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 |
5 | export default class Rtl extends Component {
6 | render() {
7 | const settings = {
8 | dots: true,
9 | infinite: true,
10 | slidesToShow: 3,
11 | slidesToScroll: 1,
12 | autoplay: true,
13 | autoplaySpeed: 2000,
14 | rtl: true
15 | };
16 | return (
17 |
18 |
Right to Left
19 |
20 | 1
21 | 2
22 | 3
23 | 4
24 | 5
25 | 6
26 |
27 |
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/PauseOnHover.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class PauseOnHover extends Component {
5 | render() {
6 | var settings = {
7 | dots: true,
8 | infinite: true,
9 | slidesToShow: 3,
10 | slidesToScroll: 1,
11 | autoplay: true,
12 | autoplaySpeed: 2000,
13 | pauseOnHover: true
14 | };
15 | return (
16 |
17 |
Pause On Hover
18 |
19 | 1
20 | 2
21 | 3
22 | 4
23 | 5
24 | 6
25 |
26 |
27 | );
28 | }
29 | }
--------------------------------------------------------------------------------
/examples/Fade.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 | import {baseUrl} from './config'
4 |
5 | export default class Fade extends Component {
6 | render() {
7 | const settings = {
8 | dots: true,
9 | fade: true,
10 | infinite: true,
11 | speed: 500,
12 | slidesToShow: 1,
13 | slidesToScroll: 1
14 | };
15 | return (
16 |
17 |
Fade
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 | }
--------------------------------------------------------------------------------
/examples/FocusOnSelect.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class FocusOnSelect extends Component {
5 | render() {
6 | const settings = {
7 | focusOnSelect: true,
8 | infinite: true,
9 | slidesToShow: 3,
10 | slidesToScroll: 1,
11 | speed: 500
12 | };
13 | return (
14 |
15 |
FocusOnSelect
16 |
Click on any slide to select and make it current slide
17 |
18 | 1
19 | 2
20 | 3
21 | 4
22 | 5
23 | 6
24 |
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/MultipleItems.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class MultipleItems extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | speed: 500,
10 | slidesToShow: 3,
11 | slidesToScroll: 3
12 | };
13 | return (
14 |
15 |
Multiple items
16 |
17 | 1
18 | 2
19 | 3
20 | 4
21 | 5
22 | 6
23 | 7
24 | 8
25 | 9
26 |
27 |
28 | );
29 | }
30 | }
--------------------------------------------------------------------------------
/examples/LazyLoad.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 | import {baseUrl} from './config'
4 |
5 | export default class LazyLoad extends Component {
6 | render() {
7 | const settings = {
8 | dots: true,
9 | lazyLoad: true,
10 | infinite: true,
11 | speed: 500,
12 | slidesToShow: 1,
13 | slidesToScroll: 1,
14 | initialSlide: 2
15 | };
16 | return (
17 |
18 |
Lazy Load
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/CenterMode.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class CenterMode extends Component {
5 | render() {
6 | const settings = {
7 | className: 'center',
8 | centerMode: true,
9 | infinite: true,
10 | centerPadding: '60px',
11 | slidesToShow: 3,
12 | speed: 500
13 | };
14 | return (
15 |
16 |
Center Mode
17 |
18 | 1
19 | 2
20 | 3
21 | 4
22 | 5
23 | 6
24 | 7
25 | 8
26 | 9
27 |
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/VariableWidth.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class VariableWidth extends Component {
5 | render() {
6 | const settings = {
7 | className: 'slider variable-width',
8 | dots: true,
9 | infinite: true,
10 | centerMode: true,
11 | slidesToShow: 1,
12 | slidesToScroll: 1,
13 | variableWidth: true
14 | };
15 | return (
16 |
17 |
Variable width
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 | }
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/CustomSlides.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | class CustomSlide extends Component {
5 | render() {
6 | const {index, ...props} = this.props
7 | return (
8 | {index}
9 | )
10 | }
11 | }
12 |
13 | export default class SimpleSlider extends Component {
14 | render() {
15 | const settings = {
16 | dots: true,
17 | infinite: true,
18 | speed: 500,
19 | slidesToShow: 1,
20 | slidesToScroll: 1,
21 | };
22 | return (
23 |
24 |
Custom Slides
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/examples/CustomPaging.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 | import {baseUrl} from './config'
4 |
5 | export default class CenterMode extends Component {
6 | render() {
7 | const settings = {
8 | customPaging: function(i) {
9 | return
10 | },
11 | dots: true,
12 | dotsClass: 'slick-dots slick-thumb',
13 | infinite: true,
14 | speed: 500,
15 | slidesToShow: 1,
16 | slidesToScroll: 1
17 | };
18 | return (
19 |
20 |
Custom Paging
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/SwipeToSlide.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class SwipeToSlide extends Component {
5 | render() {
6 | const settings = {
7 | className: 'center',
8 | infinite: true,
9 | centerPadding: '60px',
10 | slidesToShow: 5,
11 | swipeToSlide: true,
12 | afterChange: function (index) {
13 | console.log(`Slider Changed to: ${index + 1}, background: #222; color: #bada55`);
14 | }
15 | };
16 | return (
17 |
18 |
Swipe To Slide
19 |
20 | 1
21 | 2
22 | 3
23 | 4
24 | 5
25 | 6
26 | 7
27 | 8
28 | 9
29 |
30 |
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/SlideChangeHooks.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class SlideChangeHooks extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | speed: 500,
10 | slidesToShow: 1,
11 | slidesToScroll: 1,
12 | beforeChange: function (currentSlide, nextSlide) {
13 | console.log('before change', currentSlide, nextSlide);
14 | },
15 | afterChange: function (currentSlide) {
16 | console.log('after change', currentSlide);
17 | },
18 | };
19 | return (
20 |
21 |
beforeChange and afterChange hooks
22 |
23 | 1
24 | 2
25 | 3
26 | 4
27 | 5
28 | 6
29 |
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/VerticalMode.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class VerticalMode extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | slidesToShow: 3,
10 | slidesToScroll: 1,
11 | vertical: true,
12 | verticalSwiping: true,
13 | beforeChange: function (currentSlide, nextSlide) {
14 | console.log('before change', currentSlide, nextSlide);
15 | },
16 | afterChange: function (currentSlide) {
17 | console.log('after change', currentSlide);
18 | },
19 | };
20 | return (
21 |
22 |
Vertical Mode
23 |
24 | 1
25 | 2
26 | 3
27 | 4
28 | 5
29 | 6
30 |
31 |
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/examples/AdaptiveHeight.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class AdaptiveHeight extends Component {
5 | render() {
6 | var settings = {
7 | className: '',
8 | dots: true,
9 | infinite: true,
10 | slidesToShow: 1,
11 | slidesToScroll: 1,
12 | adaptiveHeight: true
13 | };
14 | return (
15 |
16 |
Adaptive height
17 |
18 | 1
19 |
23 |
24 |
3
25 |
See ....
26 |
Height is adaptive
27 |
28 |
29 |
4
30 |
31 |
32 |
5
33 |
34 |
35 |
6
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/VerticalSwipeToSlide.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class VerticalSwipeToSlide extends Component {
5 | render() {
6 | const settings = {
7 | dots: true,
8 | infinite: true,
9 | slidesToShow: 3,
10 | slidesToScroll: 1,
11 | vertical: true,
12 | verticalSwiping: true,
13 | swipeToSlide: true,
14 | beforeChange: function (currentSlide, nextSlide) {
15 | console.log('before change', currentSlide, nextSlide);
16 | },
17 | afterChange: function (currentSlide) {
18 | console.log('after change', currentSlide);
19 | },
20 | };
21 | return (
22 |
23 |
Vertical Mode with Swipe To Slide
24 |
25 | 1
26 | 2
27 | 3
28 | 4
29 | 5
30 | 6
31 |
32 |
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/examples/DynamicSlides.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class DynamicSlides extends Component {
5 | constructor(props) {
6 | super(props)
7 | this.state = {
8 | slides: [1, 2, 3, 4, 5, 6]
9 | }
10 | this.click = this.click.bind(this)
11 | }
12 | click() {
13 | const {slides} = this.state
14 | this.setState({
15 | slides: slides.length === 6 ? [1, 2, 3, 4, 5, 6, 7, 8, 9] : [1, 2, 3, 4, 5, 6]
16 | })
17 | }
18 | render() {
19 | const settings = {
20 | dots: true,
21 | infinite: true,
22 | speed: 500,
23 | slidesToShow: 3,
24 | slidesToScroll: 3
25 | };
26 | return (
27 |
28 |
Dynamic slides
29 |
30 |
31 | {this.state.slides.map(function (slide) {
32 | return {slide}
33 | })}
34 |
35 |
36 | );
37 | }
38 | }
--------------------------------------------------------------------------------
/src/initial-state.js:
--------------------------------------------------------------------------------
1 | var initialState = {
2 | animating: false,
3 | dragging: false,
4 | autoPlayTimer: null,
5 | currentDirection: 0,
6 | currentLeft: null,
7 | currentSlide: 0,
8 | direction: 1,
9 | listWidth: null,
10 | listHeight: null,
11 | // loadIndex: 0,
12 | slideCount: null,
13 | slideWidth: null,
14 | slideHeight: null,
15 | // sliding: false,
16 | // slideOffset: 0,
17 | swipeLeft: null,
18 | touchObject: {
19 | startX: 0,
20 | startY: 0,
21 | curX: 0,
22 | curY: 0
23 | },
24 |
25 | lazyLoadedList: [],
26 |
27 | // added for react
28 | initialized: false,
29 | edgeDragged: false,
30 | swiped: false, // used by swipeEvent. differentites between touch and swipe.
31 | trackStyle: {},
32 | trackWidth: 0
33 |
34 | // Removed
35 | // transformsEnabled: false,
36 | // $nextArrow: null,
37 | // $prevArrow: null,
38 | // $dots: null,
39 | // $list: null,
40 | // $slideTrack: null,
41 | // $slides: null,
42 | };
43 |
44 | module.exports = initialState;
45 |
--------------------------------------------------------------------------------
/webpack.config.dist.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: './src/index',
6 |
7 | output: {
8 | library: 'Slider',
9 | libraryTarget: 'umd',
10 | path: path.join(__dirname, 'dist')
11 | },
12 |
13 | module: {
14 | loaders: [
15 | {test: /\.jsx$/, loaders: ['babel']},
16 | {test: /\.js$/, loaders: ['babel'], exclude: /node_modules/}
17 | ]
18 | },
19 |
20 | resolve: {
21 | extensions: ['', '.js', '.jsx']
22 | },
23 |
24 | externals: [
25 | {
26 | 'react': {
27 | root: 'React',
28 | commonjs2: 'react',
29 | commonjs: 'react',
30 | amd: 'react'
31 | },
32 | 'react-dom': {
33 | root: 'ReactDOM',
34 | commonjs2: 'react-dom',
35 | commonjs: 'react-dom',
36 | amd: 'react-dom'
37 | }
38 | }
39 | ],
40 |
41 | node: {
42 | Buffer: false
43 | },
44 |
45 | plugins: [
46 | new webpack.DefinePlugin({
47 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
48 | })
49 | ]
50 | };
51 |
--------------------------------------------------------------------------------
/examples/SlickGoTo.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 | import {baseUrl} from './config'
4 |
5 | export default class SlickGoTo extends Component {
6 | constructor(props) {
7 | super(props)
8 | this.changeHandler = this.changeHandler.bind(this)
9 | }
10 | changeHandler(e) {
11 | this.refs.slider.slickGoTo(e.target.value)
12 | }
13 | render() {
14 | const settings = {
15 | dots: false,
16 | infinite: true,
17 | speed: 500,
18 | slidesToShow: 1,
19 | slidesToScroll: 1,
20 | };
21 | return (
22 |
23 |
Slick Go To
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Kiran Abburi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var autoprefixer = require('autoprefixer-core');
4 |
5 | module.exports = {
6 | devtool: '#inline-source-map',
7 | entry: {
8 | 'docs.js': [
9 | './docs/index.jsx',
10 | // 'webpack/hot/only-dev-server',
11 | // 'webpack-dev-server/client?http://localhost:8000'
12 | ]
13 | },
14 | output: {
15 | path: path.join(__dirname, 'build'),
16 | filename: '[name]'
17 | },
18 | module: {
19 | loaders: [
20 | {test: /\.jsx$/, loaders: ['babel']},
21 | {test: /\.js$/, loaders: ['babel'], exclude: /node_modules/},
22 | {
23 | test: /\.scss$/,
24 | loader: 'style!css!sass?outputStyle=expanded&' + 'includePaths[]=' +
25 | (path.resolve(__dirname, './node_modules'))
26 | },
27 | { test: /\.md$/, loader: 'html!markdown' }
28 | ]
29 | },
30 | postcss: [ autoprefixer({ browsers: ['last 2 version'] }) ],
31 | resolve: {
32 | extensions: ['', '.js', '.jsx']
33 | },
34 | plugins: [
35 | // new webpack.HotModuleReplacementPlugin(),
36 | new webpack.NoErrorsPlugin(),
37 | new webpack.IgnorePlugin(/vertx/)
38 | ]
39 | };
40 |
--------------------------------------------------------------------------------
/examples/PreviousNextMethods.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class PreviousNextMethods extends Component {
5 | constructor(props) {
6 | super(props)
7 | this.next = this.next.bind(this)
8 | this.previous = this.previous.bind(this)
9 | }
10 | next() {
11 | this.slider.slickNext()
12 | }
13 | previous() {
14 | this.slider.slickPrev()
15 | }
16 | render() {
17 | const settings = {
18 | dots: true,
19 | infinite: true,
20 | speed: 500,
21 | slidesToShow: 1,
22 | slidesToScroll: 1,
23 | };
24 | return (
25 |
26 |
Previous and Next methods
27 |
this.slider = c } {...settings}>
28 | 1
29 | 2
30 | 3
31 | 4
32 | 5
33 | 6
34 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/default-props.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | var defaultProps = {
4 | className: '',
5 | accessibility: true,
6 | adaptiveHeight: false,
7 | arrows: true,
8 | autoplay: false,
9 | autoplaySpeed: 3000,
10 | centerMode: false,
11 | centerPadding: '50px',
12 | cssEase: 'ease',
13 | customPaging: function(i) {
14 | return ;
15 | },
16 | dots: false,
17 | dotsClass: 'slick-dots',
18 | draggable: true,
19 | easing: 'linear',
20 | edgeFriction: 0.35,
21 | fade: false,
22 | focusOnSelect: false,
23 | infinite: true,
24 | initialSlide: 0,
25 | lazyLoad: false,
26 | pauseOnHover: true,
27 | responsive: null,
28 | rtl: false,
29 | slide: 'div',
30 | slidesToShow: 1,
31 | slidesToScroll: 1,
32 | speed: 500,
33 | swipe: true,
34 | swipeToSlide: false,
35 | touchMove: true,
36 | touchThreshold: 5,
37 | useCSS: true,
38 | variableWidth: false,
39 | vertical: false,
40 | waitForAnimate: true,
41 | afterChange: null,
42 | beforeChange: null,
43 | edgeEvent: null,
44 | init: null,
45 | swipeEvent: null,
46 | // nextArrow, prevArrow are react componets
47 | nextArrow: null,
48 | prevArrow: null
49 | };
50 |
51 | module.exports = defaultProps;
52 |
--------------------------------------------------------------------------------
/examples/CustomArrows.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | function SampleNextArrow(props) {
5 | const {className, style, onClick} = props
6 | return (
7 |
12 | );
13 | }
14 |
15 | function SamplePrevArrow(props) {
16 | const {className, style, onClick} = props
17 | return (
18 |
23 | );
24 | }
25 |
26 |
27 | export default class CustomArrows extends Component {
28 | render() {
29 | const settings = {
30 | dots: true,
31 | infinite: true,
32 | slidesToShow: 3,
33 | slidesToScroll: 1,
34 | nextArrow: ,
35 | prevArrow:
36 | };
37 | return (
38 |
39 |
Custom Arrows
40 |
41 | 1
42 | 2
43 | 3
44 | 4
45 | 5
46 | 6
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/examples/Responsive.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Slider from '../src/slider'
3 |
4 | export default class Responsive extends Component {
5 | render() {
6 | var settings = {
7 | dots: true,
8 | infinite: false,
9 | speed: 500,
10 | slidesToShow: 4,
11 | slidesToScroll: 4,
12 | initialSlide: 0,
13 | responsive: [{
14 | breakpoint: 1024,
15 | settings: {
16 | slidesToShow: 3,
17 | slidesToScroll: 3,
18 | infinite: true,
19 | dots: true
20 | }
21 | }, {
22 | breakpoint: 600,
23 | settings: {
24 | slidesToShow: 2,
25 | slidesToScroll: 2,
26 | initialSlide: 2
27 | }
28 | }, {
29 | breakpoint: 480,
30 | settings: {
31 | slidesToShow: 1,
32 | slidesToScroll: 1
33 | }
34 | }]
35 | };
36 | return (
37 |
38 |
Responsive
39 |
40 | 1
41 | 2
42 | 3
43 | 4
44 | 5
45 | 6
46 | 7
47 | 8
48 |
49 |
50 | );
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/src/dots.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import classnames from 'classnames';
5 |
6 | var getDotCount = function (spec) {
7 | var dots;
8 | dots = Math.ceil(spec.slideCount / spec.slidesToScroll);
9 | return dots;
10 | };
11 |
12 |
13 | export class Dots extends React.Component {
14 | clickHandler(options, e) {
15 | // In Autoplay the focus stays on clicked button even after transition
16 | // to next slide. That only goes away by click somewhere outside
17 | e.preventDefault();
18 | this.props.clickHandler(options);
19 | }
20 | render() {
21 |
22 | var dotCount = getDotCount({
23 | slideCount: this.props.slideCount,
24 | slidesToScroll: this.props.slidesToScroll
25 | });
26 |
27 | // Apply join & split to Array to pre-fill it for IE8
28 | //
29 | // Credit: http://stackoverflow.com/a/13735425/1849458
30 | var dots = Array.apply(null, Array(dotCount + 1).join('0').split('')).map((x, i) => {
31 |
32 | var leftBound = (i * this.props.slidesToScroll);
33 | var rightBound = (i * this.props.slidesToScroll) + (this.props.slidesToScroll - 1);
34 | var className = classnames({
35 | 'slick-active': (this.props.currentSlide >= leftBound) && (this.props.currentSlide <= rightBound)
36 | });
37 |
38 | var dotOptions = {
39 | message: 'dots',
40 | index: i,
41 | slidesToScroll: this.props.slidesToScroll,
42 | currentSlide: this.props.currentSlide
43 | };
44 |
45 | var onClick = this.clickHandler.bind(this, dotOptions);
46 |
47 | return (
48 |
49 | {React.cloneElement(this.props.customPaging(i), {onClick})}
50 |
51 | );
52 | });
53 |
54 | return (
55 |
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/docs/_style.scss:
--------------------------------------------------------------------------------
1 | h3 {
2 | background: $primary-color;
3 | color: #fff;
4 | font-size: 36px;
5 | line-height: 100px;
6 | margin: 10px;
7 | padding: 2%;
8 | position: relative;
9 | text-align: center;
10 | }
11 | .variable-width .slick-slide p {
12 | background: $primary-color;
13 | height: 100px;
14 | color: #fff;
15 | margin: 5px;
16 | line-height: 100px;
17 | text-align: center;
18 | }
19 | .center .slick-center h3 {
20 | color: #e67e22;
21 | opacity: 1;
22 | transform: scale(1.08);
23 | }
24 | .center h3{
25 | opacity: 0.8;
26 | transition: all 300ms ease;
27 | }
28 | .content {
29 | padding: 20px;
30 | margin: auto;
31 | width: 90%;
32 | }
33 | .slick-slide .image {
34 | padding: 10px;
35 | }
36 | .slick-slide img {
37 | border: 5px solid #FFF;
38 | display: block;
39 | margin: auto;
40 | }
41 | .slick-slide img.slick-loading {
42 | border: 0
43 | }
44 | .slick-slider {
45 | margin: 30px auto 50px;
46 | }
47 | .slick-dots {
48 | margin-left: 0;
49 | }
50 | .slick-thumb {
51 | bottom: -45px;
52 | li {
53 | width: 60px;
54 | height: 45px;
55 | img {
56 | filter: grayscale(100%);
57 | }
58 | &.slick-active {
59 | img {
60 | filter: grayscale(0%);
61 | }
62 | }
63 | }
64 | }
65 | @media (max-width: 768px) {
66 | h3 {
67 | font-size:24px;
68 | }
69 | .center {
70 | margin-left: -40px;
71 | margin-right: -40px;
72 | }
73 | .center .slick-center h3 {
74 | color: #e67e22;
75 | opacity: 1;
76 | transform: scale(1);
77 | }
78 | .center h3 {
79 | opacity: 0.8;
80 | transform: scale(0.95);
81 | transition: all 300ms ease;
82 | }
83 | }
84 | // just like in the regular library, we cannot simply have a vertical
85 | // slider fill available space like in the horizontal case
86 | //
87 | // we have to therefore set the height of a slide in a vertical slider
88 | // explicitly in CSS or otherwise
89 | .slick-vertical .slick-slide {
90 | height: 180px;
91 | }
92 |
--------------------------------------------------------------------------------
/__tests__/arrows.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Arrow component tests
3 | */
4 |
5 | sinon.stub(console, 'error');
6 |
7 | import {render, shallow} from 'enzyme';
8 | import React from 'react';
9 | import sinon from 'sinon';
10 |
11 | import { NextArrow, PrevArrow } from '../src/arrows';
12 |
13 | function CustomArrow(props) {
14 | return (
15 |
19 | );
20 | }
21 |
22 | describe('Previous arrows', () => {
23 | it('should render arrow', () => {
24 | const wrapper = shallow();
25 | expect(wrapper.find('button')).toHaveLength(1);
26 | });
27 |
28 | it('should not result in errors', () => {
29 | shallow();
30 |
31 | expect(console.error.called).toBe(false);
32 | });
33 |
34 | it('should pass slide data to custom arrow', () => {
35 | let elAttributes;
36 | let arr =
37 |
38 | const wrapper = render();
39 |
40 | elAttributes = wrapper.find('.sample')[0].attribs;
41 | expect(elAttributes['data-currentslide']).toBe('3');
42 | expect(elAttributes['data-slidecount']).toBe('5');
43 | });
44 | });
45 |
46 | describe('Next arrows', () => {
47 | it('should render arrow', () => {
48 | const wrapper = shallow();
49 | expect(wrapper.find('button')).toHaveLength(1);
50 | });
51 |
52 | it('should not result in errors', () => {
53 | shallow();
54 |
55 | expect(console.error.called).toBe(false);
56 | });
57 |
58 | it('should pass slide data to custom arrow', () => {
59 | let elAttributes;
60 | let arr =
61 |
62 | const wrapper = render();
63 |
64 | elAttributes = wrapper.find('.sample')[0].attribs;
65 | expect(elAttributes['data-currentslide']).toBe('6');
66 | expect(elAttributes['data-slidecount']).toBe('9');
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/docs/demos.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import Slider from '../src/slider';
5 |
6 | import SimpleSlider from '../examples/SimpleSlider'
7 | import SlideChangeHooks from '../examples/SlideChangeHooks'
8 | import MultipleItems from '../examples/MultipleItems'
9 | import Responsive from '../examples/Responsive'
10 | import UnevenSetsInfinite from '../examples/UnevenSetsInfinite'
11 | import UnevenSetsFinite from '../examples/UnevenSetsFinite'
12 | import CenterMode from '../examples/CenterMode'
13 | import FocusOnSelect from '../examples/FocusOnSelect'
14 | import AutoPlay from '../examples/AutoPlay'
15 | import PauseOnHover from '../examples/PauseOnHover'
16 | import Rtl from '../examples/Rtl'
17 | import VariableWidth from '../examples/VariableWidth'
18 | import AdaptiveHeight from '../examples/AdaptiveHeight'
19 | import LazyLoad from '../examples/LazyLoad'
20 | import Fade from '../examples/Fade'
21 | import SlickGoTo from '../examples/SlickGoTo'
22 | import CustomArrows from '../examples/CustomArrows'
23 | import PreviousNextMethods from '../examples/PreviousNextMethods'
24 | import DynamicSlides from '../examples/DynamicSlides'
25 | import VerticalMode from '../examples/VerticalMode'
26 | import SwipeToSlide from '../examples/SwipeToSlide'
27 | import VerticalSwipeToSlide from '../examples/VerticalSwipeToSlide'
28 | import CustomPaging from '../examples/CustomPaging'
29 | import CustomSlides from '../examples/CustomSlides'
30 |
31 | export default class App extends React.Component {
32 | render() {
33 | return (
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/arrows.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import classnames from 'classnames';
5 | import Helpers from './mixins/helpers';
6 |
7 | export class PrevArrow extends React.Component {
8 | clickHandler(options, e) {
9 | if (e) { e.preventDefault(); }
10 | this.props.clickHandler(options, e);
11 | }
12 | render() {
13 | var prevClasses = {'slick-arrow': true, 'slick-prev': true};
14 | var prevHandler = this.clickHandler.bind(this, {message: 'previous'});
15 |
16 | if (!this.props.infinite && (this.props.currentSlide === 0 || this.props.slideCount <= this.props.slidesToShow)) {
17 | prevClasses['slick-disabled'] = true;
18 | prevHandler = null;
19 | }
20 |
21 | var prevArrowProps = {
22 | key: '0',
23 | 'data-role': 'none',
24 | className: classnames(prevClasses),
25 | style: {display: 'block'},
26 | onClick: prevHandler
27 | };
28 | var customProps = {
29 | currentSlide: this.props.currentSlide,
30 | slideCount: this.props.slideCount
31 | };
32 | var prevArrow;
33 |
34 | if (this.props.prevArrow) {
35 | prevArrow = React.cloneElement(this.props.prevArrow, { ...prevArrowProps, ...customProps });
36 | } else {
37 | prevArrow = ;
38 | }
39 |
40 | return prevArrow;
41 | }
42 | }
43 |
44 |
45 | export class NextArrow extends React.Component {
46 | clickHandler(options, e) {
47 | if (e) { e.preventDefault(); }
48 | this.props.clickHandler(options, e);
49 | }
50 | render() {
51 | var nextClasses = {'slick-arrow': true, 'slick-next': true};
52 | var nextHandler = this.clickHandler.bind(this, {message: 'next'});
53 |
54 | if (!Helpers.canGoNext(this.props)) {
55 | nextClasses['slick-disabled'] = true;
56 | nextHandler = null;
57 | }
58 |
59 | var nextArrowProps = {
60 | key: '1',
61 | 'data-role': 'none',
62 | className: classnames(nextClasses),
63 | style: {display: 'block'},
64 | onClick: nextHandler
65 | };
66 | var customProps = {
67 | currentSlide: this.props.currentSlide,
68 | slideCount: this.props.slideCount
69 | };
70 | var nextArrow;
71 |
72 | if (this.props.nextArrow) {
73 | nextArrow = React.cloneElement(this.props.nextArrow, { ...nextArrowProps, ...customProps });
74 | } else {
75 | nextArrow = ;
76 | }
77 |
78 | return nextArrow;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-slick",
3 | "version": "0.14.10",
4 | "description": " React port of slick carousel",
5 | "main": "./lib",
6 | "scripts": {
7 | "start": "gulp server",
8 | "prepublish": "babel ./src --out-dir ./lib && gulp dist",
9 | "test": "jest",
10 | "dev-test": "jest --watch",
11 | "lint": "eslint src"
12 | },
13 | "author": "Kiran Abburi",
14 | "license": "MIT",
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/akiran/react-slick"
18 | },
19 | "keywords": [
20 | "slick",
21 | "carousel",
22 | "Image slider",
23 | "orbit",
24 | "slider",
25 | "react-component"
26 | ],
27 | "devDependencies": {
28 | "autoprefixer-core": "^6.0.1",
29 | "babel-cli": "^6.16.0",
30 | "babel-core": "^6.16.0",
31 | "babel-eslint": "^7.0.0",
32 | "babel-jest": "^19.0.0",
33 | "babel-loader": "^6.2.5",
34 | "babel-plugin-transform-object-assign": "^6.8.0",
35 | "babel-polyfill": "^6.16.0",
36 | "babel-preset-airbnb": "^2.1.1",
37 | "babel-preset-es2015": "^6.16.0",
38 | "babel-preset-react": "^6.16.0",
39 | "css-loader": "^0.28.0",
40 | "deepmerge": "^1.1.0",
41 | "del": "^2.2.2",
42 | "enzyme": "^2.8.2",
43 | "es5-shim": "^4.5.9",
44 | "eslint": "^3.6.1",
45 | "eslint-plugin-react": "^6.3.0",
46 | "express": "^4.14.0",
47 | "foundation-apps": "^1.2.0",
48 | "gulp": "^3.9.1",
49 | "gulp-sass": "^3.1.0",
50 | "jasmine-core": "^2.5.2",
51 | "jest": "^19.0.2",
52 | "json-loader": "^0.5.4",
53 | "node-sass": "^4.5.2",
54 | "postcss-loader": "^1.3.3",
55 | "react": "^15.3.2",
56 | "react-addons-test-utils": "^15.3.2",
57 | "react-dom": "^15.3.2",
58 | "react-test-renderer": "^15.5.4",
59 | "run-sequence": "^1.2.2",
60 | "sass-loader": "^6.0.3",
61 | "sinon": "^2.1.0",
62 | "style-loader": "^0.16.1",
63 | "webpack": "^1.13.2",
64 | "webpack-dev-server": "^1.16.1"
65 | },
66 | "dependencies": {
67 | "classnames": "^2.2.5",
68 | "create-react-class": "^15.5.2",
69 | "json2mq": "^0.2.0",
70 | "object-assign": "^4.1.0",
71 | "slick-carousel": "^1.6.0",
72 | "enquire.js": "^2.1.6"
73 | },
74 | "peerDependencies": {
75 | "react": "^0.14.0 || ^15.0.1",
76 | "react-dom": "^0.14.0 || ^15.0.1"
77 | },
78 | "jest": {
79 | "setupFiles": [
80 | "./test-setup.js"
81 | ]
82 | },
83 | "npmName": "react-slick",
84 | "npmFileMap": [
85 | {
86 | "basePath": "/dist/",
87 | "files": [
88 | "*.js"
89 | ]
90 | }
91 | ],
92 | "bugs": {
93 | "url": "https://github.com/akiran/react-slick/issues"
94 | },
95 | "homepage": "https://github.com/akiran/react-slick"
96 | }
97 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var del = require('del');
5 | var sass = require('gulp-sass');
6 | var webpack = require('webpack');
7 | var WebpackDevServer = require('webpack-dev-server');
8 | var runSequence = require('run-sequence');
9 | var assign = require('object-assign');
10 |
11 | gulp.task('default', ['watch', 'server']);
12 |
13 | gulp.task('clean', function () {
14 | return del(['./build/*']);
15 | });
16 |
17 | gulp.task('copy', function () {
18 | gulp.src('./docs/index.html')
19 | .pipe(gulp.dest('./build'));
20 | gulp.src('./docs/img/**/*')
21 | .pipe(gulp.dest('./build/img'));
22 | gulp.src('./node_modules/slick-carousel/slick/fonts/*')
23 | .pipe(gulp.dest('./build/fonts'));
24 | return gulp.src('./node_modules/slick-carousel/slick/ajax-loader.gif')
25 | .pipe(gulp.dest('./build'));
26 | });
27 |
28 | gulp.task('sass', function () {
29 | return gulp.src(['./docs/**/*.{scss,sass}'])
30 | .pipe(sass({ includePaths: ['bower_components', 'node_modules'], errLogToConsole: true}))
31 | .pipe(gulp.dest('./build'));
32 | });
33 |
34 | gulp.task('watch', ['copy', 'sass'], function () {
35 | gulp.watch(['./docs/**/*.{scss,sass}'], ['sass']);
36 | gulp.watch(['./docs/index.html'], ['copy']);
37 | });
38 |
39 | gulp.task('server', ['copy', 'sass'], function (callback) {
40 | var myConfig = require('./webpack.config');
41 | myConfig.plugins = myConfig.plugins.concat(
42 | new webpack.DefinePlugin({
43 | 'process.env': {
44 | 'NODE_ENV': JSON.stringify('dev_docs')
45 | }
46 | })
47 | );
48 |
49 | new WebpackDevServer(webpack(myConfig), {
50 | contentBase: './build',
51 | hot: true,
52 | debug: true
53 | }).listen(8080, '0.0.0.0', function (err, result) {
54 | if (err) {
55 | console.log(err);
56 | }
57 | });
58 | callback();
59 | });
60 |
61 |
62 | // gulp tasks for building dist files
63 | gulp.task('dist-clean', function () {
64 | return del(['./dist/*']);
65 | });
66 |
67 | var distConfig = require('./webpack.config.dist.js');
68 | gulp.task('dist-unmin', function (cb) {
69 | var unminConfig = assign({}, distConfig);
70 | unminConfig.output.filename = 'react-slick.js';
71 | return webpack(unminConfig, function (err, stat) {
72 | console.error(err);
73 | cb();
74 | });
75 | });
76 |
77 |
78 | gulp.task('dist-min', function (cb) {
79 | var minConfig = assign({}, distConfig);
80 | minConfig.output.filename = 'react-slick.min.js';
81 | minConfig.plugins = minConfig.plugins.concat(
82 | new webpack.optimize.UglifyJsPlugin({
83 | compressor: {
84 | warnings: false
85 | }
86 | })
87 | );
88 | return webpack(minConfig, function (err, stat) {
89 | console.error(err);
90 | cb();
91 | });
92 | });
93 |
94 | gulp.task('dist', function (cb) {
95 | runSequence('dist-clean', 'dist-unmin', 'dist-min', cb);
96 | });
97 |
--------------------------------------------------------------------------------
/src/slider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import {InnerSlider} from './inner-slider';
5 | import assign from 'object-assign';
6 | import json2mq from 'json2mq';
7 | import defaultProps from './default-props';
8 | import enquire from 'enquire.js';
9 |
10 | export default class Slider extends React.Component {
11 | constructor(props) {
12 | super(props)
13 | this.state = {
14 | breakpoint: null
15 | };
16 | this._responsiveMediaHandlers = [];
17 | this.innerSliderRefHandler = this.innerSliderRefHandler.bind(this)
18 | }
19 | innerSliderRefHandler(ref) {
20 | this.innerSlider = ref;
21 | }
22 | media(query, handler) {
23 | enquire.register(query, handler);
24 | this._responsiveMediaHandlers.push({query, handler});
25 | }
26 | componentWillMount() {
27 | if (this.props.responsive) {
28 | var breakpoints = this.props.responsive.map(breakpt => breakpt.breakpoint);
29 | breakpoints.sort((x, y) => x - y);
30 |
31 | breakpoints.forEach((breakpoint, index) => {
32 | var bQuery;
33 | if (index === 0) {
34 | bQuery = json2mq({minWidth: 0, maxWidth: breakpoint});
35 | } else {
36 | bQuery = json2mq({minWidth: breakpoints[index-1], maxWidth: breakpoint});
37 | }
38 | this.media(bQuery, () => {
39 | this.setState({breakpoint: breakpoint});
40 | })
41 | });
42 |
43 | // Register media query for full screen. Need to support resize from small to large
44 | var query = json2mq({minWidth: breakpoints.slice(-1)[0]});
45 |
46 | this.media(query, () => {
47 | this.setState({breakpoint: null});
48 | });
49 | }
50 | }
51 |
52 | componentWillUnmount() {
53 | this._responsiveMediaHandlers.forEach(function(obj) {
54 | enquire.unregister(obj.query, obj.handler);
55 | });
56 | }
57 |
58 | slickPrev() {
59 | this.innerSlider.slickPrev();
60 | }
61 |
62 | slickNext() {
63 | this.innerSlider.slickNext();
64 | }
65 |
66 | slickGoTo(slide) {
67 | this.innerSlider.slickGoTo(slide)
68 | }
69 |
70 | render() {
71 | var settings;
72 | var newProps;
73 | if (this.state.breakpoint) {
74 | newProps = this.props.responsive.filter(resp => resp.breakpoint === this.state.breakpoint);
75 | settings = newProps[0].settings === 'unslick' ? 'unslick' : assign({}, this.props, newProps[0].settings);
76 | } else {
77 | settings = assign({}, defaultProps, this.props);
78 | }
79 |
80 | var children = this.props.children;
81 | if(!Array.isArray(children)) {
82 | children = [children]
83 | }
84 |
85 | // Children may contain false or null, so we should filter them
86 | children = children.filter(function(child){
87 | return !!child
88 | })
89 |
90 | if (settings === 'unslick') {
91 | // if 'unslick' responsive breakpoint setting used, just return the tag nested HTML
92 | return (
93 | {children}
94 | );
95 | } else {
96 | return (
97 |
98 | {children}
99 |
100 | );
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/track.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import assign from 'object-assign';
5 | import classnames from 'classnames';
6 |
7 | var getSlideClasses = (spec) => {
8 | var slickActive, slickCenter, slickCloned;
9 | var centerOffset, index;
10 |
11 | if (spec.rtl) {
12 | index = spec.slideCount - 1 - spec.index;
13 | } else {
14 | index = spec.index;
15 | }
16 |
17 | slickCloned = (index < 0) || (index >= spec.slideCount);
18 | if (spec.centerMode) {
19 | centerOffset = Math.floor(spec.slidesToShow / 2);
20 | slickCenter = (index - spec.currentSlide) % spec.slideCount === 0;
21 | if ((index > spec.currentSlide - centerOffset - 1) && (index <= spec.currentSlide + centerOffset)) {
22 | slickActive = true;
23 | }
24 | } else {
25 | slickActive = (spec.currentSlide <= index) && (index < spec.currentSlide + spec.slidesToShow);
26 | }
27 | return classnames({
28 | 'slick-slide': true,
29 | 'slick-active': slickActive,
30 | 'slick-center': slickCenter,
31 | 'slick-cloned': slickCloned
32 | });
33 | };
34 |
35 | var getSlideStyle = function (spec) {
36 | var style = {};
37 |
38 | if (spec.variableWidth === undefined || spec.variableWidth === false) {
39 | style.width = spec.slideWidth;
40 | }
41 |
42 | if (spec.fade) {
43 | style.position = 'relative';
44 | style.left = -spec.index * spec.slideWidth;
45 | style.opacity = (spec.currentSlide === spec.index) ? 1 : 0;
46 | style.transition = 'opacity ' + spec.speed + 'ms ' + spec.cssEase;
47 | style.WebkitTransition = 'opacity ' + spec.speed + 'ms ' + spec.cssEase;
48 | }
49 |
50 | return style;
51 | };
52 |
53 | var getKey = (child, fallbackKey) => {
54 | // key could be a zero
55 | return (child.key === null || child.key === undefined) ? fallbackKey : child.key;
56 | };
57 |
58 | var renderSlides = function (spec) {
59 | var key;
60 | var slides = [];
61 | var preCloneSlides = [];
62 | var postCloneSlides = [];
63 | var count = React.Children.count(spec.children);
64 |
65 |
66 | React.Children.forEach(spec.children, (elem, index) => {
67 | let child;
68 | var childOnClickOptions = {
69 | message: 'children',
70 | index: index,
71 | slidesToScroll: spec.slidesToScroll,
72 | currentSlide: spec.currentSlide
73 | };
74 |
75 | if (!spec.lazyLoad | (spec.lazyLoad && spec.lazyLoadedList.indexOf(index) >= 0)) {
76 | child = elem;
77 | } else {
78 | child = ();
79 | }
80 | var childStyle = getSlideStyle(assign({}, spec, {index: index}));
81 | var slickClasses = getSlideClasses(assign({index: index}, spec));
82 | var cssClasses;
83 |
84 | if (child.props.className) {
85 | cssClasses = classnames(slickClasses, child.props.className);
86 | } else {
87 | cssClasses = slickClasses;
88 | }
89 |
90 | const onClick = function(e) {
91 | child.props && child.props.onClick && child.props.onClick(e)
92 | if (spec.focusOnSelect) {
93 | spec.focusOnSelect(childOnClickOptions)
94 | }
95 | }
96 |
97 | slides.push(React.cloneElement(child, {
98 | key: 'original' + getKey(child, index),
99 | 'data-index': index,
100 | className: cssClasses,
101 | tabIndex: '-1',
102 | style: assign({outline: 'none'}, child.props.style || {}, childStyle),
103 | onClick
104 | }));
105 |
106 | // variableWidth doesn't wrap properly.
107 | if (spec.infinite && spec.fade === false) {
108 | var infiniteCount = spec.variableWidth ? spec.slidesToShow + 1 : spec.slidesToShow;
109 |
110 | if (index >= (count - infiniteCount)) {
111 | key = -(count - index);
112 | preCloneSlides.push(React.cloneElement(child, {
113 | key: 'precloned' + getKey(child, key),
114 | 'data-index': key,
115 | className: cssClasses,
116 | style: assign({}, child.props.style || {}, childStyle),
117 | onClick
118 | }));
119 | }
120 |
121 | if (index < infiniteCount) {
122 | key = count + index;
123 | postCloneSlides.push(React.cloneElement(child, {
124 | key: 'postcloned' + getKey(child, key),
125 | 'data-index': key,
126 | className: cssClasses,
127 | style: assign({}, child.props.style || {}, childStyle),
128 | onClick
129 | }));
130 | }
131 | }
132 | });
133 |
134 | if (spec.rtl) {
135 | return preCloneSlides.concat(slides, postCloneSlides).reverse();
136 | } else {
137 | return preCloneSlides.concat(slides, postCloneSlides);
138 | }
139 |
140 |
141 | };
142 |
143 | export class Track extends React.Component {
144 | render() {
145 | var slides = renderSlides.call(this, this.props);
146 | return (
147 |
148 | { slides }
149 |
150 | );
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/mixins/trackHelper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import ReactDOM from 'react-dom';
3 | import assign from 'object-assign';
4 |
5 | var checkSpecKeys = function (spec, keysArray) {
6 | return keysArray.reduce((value, key) => {
7 | return value && spec.hasOwnProperty(key);
8 | }, true) ? null : console.error('Keys Missing', spec);
9 | };
10 |
11 | export var getTrackCSS = function(spec) {
12 | checkSpecKeys(spec, [
13 | 'left', 'variableWidth', 'slideCount', 'slidesToShow', 'slideWidth'
14 | ]);
15 |
16 | var trackWidth, trackHeight;
17 |
18 | const trackChildren = (spec.slideCount + 2 * spec.slidesToShow);
19 |
20 | if (!spec.vertical) {
21 | if (spec.variableWidth) {
22 | trackWidth = (spec.slideCount + 2*spec.slidesToShow) * spec.slideWidth;
23 | } else if (spec.centerMode) {
24 | trackWidth = (spec.slideCount + 2*(spec.slidesToShow + 1)) * spec.slideWidth;
25 | } else {
26 | trackWidth = (spec.slideCount + 2*spec.slidesToShow) * spec.slideWidth;
27 | }
28 | } else {
29 | trackHeight = trackChildren * spec.slideHeight;
30 | }
31 |
32 | var style = {
33 | opacity: 1,
34 | WebkitTransform: !spec.vertical ? 'translate3d(' + spec.left + 'px, 0px, 0px)' : 'translate3d(0px, ' + spec.left + 'px, 0px)',
35 | transform: !spec.vertical ? 'translate3d(' + spec.left + 'px, 0px, 0px)' : 'translate3d(0px, ' + spec.left + 'px, 0px)',
36 | transition: '',
37 | WebkitTransition: '',
38 | msTransform: !spec.vertical ? 'translateX(' + spec.left + 'px)' : 'translateY(' + spec.left + 'px)',
39 | };
40 |
41 | if (trackWidth) {
42 | assign(style, { width: trackWidth });
43 | }
44 |
45 | if (trackHeight) {
46 | assign(style, { height: trackHeight });
47 | }
48 |
49 | // Fallback for IE8
50 | if (window && !window.addEventListener && window.attachEvent) {
51 | if (!spec.vertical) {
52 | style.marginLeft = spec.left + 'px';
53 | } else {
54 | style.marginTop = spec.left + 'px';
55 | }
56 | }
57 |
58 | return style;
59 | };
60 |
61 | export var getTrackAnimateCSS = function (spec) {
62 | checkSpecKeys(spec, [
63 | 'left', 'variableWidth', 'slideCount', 'slidesToShow', 'slideWidth', 'speed', 'cssEase'
64 | ]);
65 |
66 | var style = getTrackCSS(spec);
67 | // useCSS is true by default so it can be undefined
68 | style.WebkitTransition = '-webkit-transform ' + spec.speed + 'ms ' + spec.cssEase;
69 | style.transition = 'transform ' + spec.speed + 'ms ' + spec.cssEase;
70 | return style;
71 | };
72 |
73 | export var getTrackLeft = function (spec) {
74 |
75 | checkSpecKeys(spec, [
76 | 'slideIndex', 'trackRef', 'infinite', 'centerMode', 'slideCount', 'slidesToShow',
77 | 'slidesToScroll', 'slideWidth', 'listWidth', 'variableWidth', 'slideHeight']);
78 |
79 | var slideOffset = 0;
80 | var targetLeft;
81 | var targetSlide;
82 | var verticalOffset = 0;
83 |
84 | if (spec.fade) {
85 | return 0;
86 | }
87 |
88 | if (spec.infinite) {
89 | if (spec.slideCount >= spec.slidesToShow) {
90 | slideOffset = (spec.slideWidth * spec.slidesToShow) * -1;
91 | verticalOffset = (spec.slideHeight * spec.slidesToShow) * -1;
92 | }
93 | if (spec.slideCount % spec.slidesToScroll !== 0) {
94 | if (spec.slideIndex + spec.slidesToScroll > spec.slideCount && spec.slideCount > spec.slidesToShow) {
95 | if(spec.slideIndex > spec.slideCount) {
96 | slideOffset = ((spec.slidesToShow - (spec.slideIndex - spec.slideCount)) * spec.slideWidth) * -1;
97 | verticalOffset = ((spec.slidesToShow - (spec.slideIndex - spec.slideCount)) * spec.slideHeight) * -1;
98 | } else {
99 | slideOffset = ((spec.slideCount % spec.slidesToScroll) * spec.slideWidth) * -1;
100 | verticalOffset = ((spec.slideCount % spec.slidesToScroll) * spec.slideHeight) * -1;
101 | }
102 | }
103 | }
104 | } else {
105 |
106 | if (spec.slideCount % spec.slidesToScroll !== 0) {
107 | if (spec.slideIndex + spec.slidesToScroll > spec.slideCount && spec.slideCount > spec.slidesToShow) {
108 | var slidesToOffset = spec.slidesToShow - (spec.slideCount % spec.slidesToScroll);
109 | slideOffset = slidesToOffset * spec.slideWidth;
110 | }
111 | }
112 | }
113 |
114 |
115 |
116 | if (spec.centerMode) {
117 | if(spec.infinite) {
118 | slideOffset += spec.slideWidth * Math.floor(spec.slidesToShow / 2);
119 | } else {
120 | slideOffset = spec.slideWidth * Math.floor(spec.slidesToShow / 2);
121 | }
122 | }
123 |
124 | if (!spec.vertical) {
125 | targetLeft = ((spec.slideIndex * spec.slideWidth) * -1) + slideOffset;
126 | } else {
127 | targetLeft = ((spec.slideIndex * spec.slideHeight) * -1) + verticalOffset;
128 | }
129 |
130 | if (spec.variableWidth === true) {
131 | var targetSlideIndex;
132 | if(spec.slideCount <= spec.slidesToShow || spec.infinite === false) {
133 | targetSlide = ReactDOM.findDOMNode(spec.trackRef).childNodes[spec.slideIndex];
134 | } else {
135 | targetSlideIndex = (spec.slideIndex + spec.slidesToShow);
136 | targetSlide = ReactDOM.findDOMNode(spec.trackRef).childNodes[targetSlideIndex];
137 | }
138 | targetLeft = targetSlide ? targetSlide.offsetLeft * -1 : 0;
139 | if (spec.centerMode === true) {
140 | if(spec.infinite === false) {
141 | targetSlide = ReactDOM.findDOMNode(spec.trackRef).children[spec.slideIndex];
142 | } else {
143 | targetSlide = ReactDOM.findDOMNode(spec.trackRef).children[(spec.slideIndex + spec.slidesToShow + 1)];
144 | }
145 |
146 | if (targetSlide) {
147 | targetLeft = targetSlide.offsetLeft * -1 + (spec.listWidth - targetSlide.offsetWidth) / 2;
148 | }
149 | }
150 | }
151 |
152 | return targetLeft;
153 | };
154 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-slick
2 |
3 | [](https://gitter.im/akiran/react-slick?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 |
6 | Carousel component built with React. It is a react port of [slick carousel](http://kenwheeler.github.io/slick/)
7 |
8 | ### Important
9 | ### Breaking changes in react-slick@0.15
10 | * slickGoTo prop is deprecated in favor of slickGoTo method. Check this [slickGoTo usage example](https://github.com/akiran/react-slick/blob/master/examples/SlickGoTo.js).
11 | * dist folder will be removed from the repo to simplify PR review process. If you are using bower or relying on the dist files in github repo, use dist files from unpkg.com
12 | ```
13 | https://unpkg.com/react-slick@0.13.6/dist/react-slick.min.js
14 | ```
15 |
16 | ### Installation
17 |
18 | ```bash
19 | npm install react-slick
20 | ```
21 |
22 | Also install slick-carousel for css and font
23 |
24 | ```bash
25 | npm install slick-carousel
26 | @import "~slick-carousel/slick/slick.css";
27 | @import "~slick-carousel/slick/slick-theme.css";
28 | ```
29 |
30 | or add cdn link in your html
31 |
32 | ```html
33 |
34 |
35 | ```
36 |
37 | ### [Demos](http://neostack.com/opensource/react-slick)
38 |
39 | ### [PlayGround](https://jsfiddle.net/kirana/20bumb4g/)
40 | Use [jsfiddle template](https://jsfiddle.net/kirana/20bumb4g/) to try react-slick with different settings.
41 |
42 | ### Filing issues
43 | Please replicate your issue with [jsfiddle template](https://jsfiddle.net/kirana/20bumb4g/) and post it along with issue to make it easy for me to debug.
44 |
45 |
46 | ### Starter Kit
47 | Checkout [yeoman generator](https://github.com/akiran/generator-react-slick) to quickly
48 | get started with react-slick.
49 |
50 | ### Example
51 |
52 | ```js
53 | var React = require('react');
54 | var Slider = require('react-slick');
55 |
56 | class SimpleSlider extends React.Component {
57 | render: function () {
58 | var settings = {
59 | dots: true,
60 | infinite: true,
61 | speed: 500,
62 | slidesToShow: 1,
63 | slidesToScroll: 1
64 | };
65 | return (
66 |
67 | 1
68 | 2
69 | 3
70 | 4
71 | 5
72 | 6
73 |
74 | );
75 | }
76 | }
77 | ```
78 |
79 | | Property | Type | Description | Working |
80 | | ------------- | ---- | ----------- | ------- |
81 | | accessibility | bool | Enables tabbing and arrow key navigation | Yes |
82 | | className | String |Additional class name for the inner slider div | Yes |
83 | | adaptiveHeight | bool | Adjust the slide's height automatically | Yes |
84 | | arrows | bool | Should we show Left and right nav arrows | Yes |
85 | | nextArrow | React Element | Use this element for the next arrow button | Yes |
86 | | prevArrow | React Element | Use this element for the prev arrow button | Yes |
87 | | autoplay | bool | Should the scroller auto scroll? | Yes |
88 | | autoplaySpeed | int | delay between each auto scoll. in ms | Yes |
89 | | centerMode | bool | Should we centre to a single item? | Yes |
90 | | centerPadding | | | |
91 | | cssEase | | | |
92 | | customPaging | func | Custom paging templates. [Example](https://github.com/akiran/react-slick/blob/master/examples/CustomPaging.js)| Yes |
93 | | dots | bool | Should we show the dots at the bottom of the gallery | Yes |
94 | | dotsClass | string | Class applied to the dots if they are enabled | Yes |
95 | | draggable | bool | Is the gallery scrollable via dragging on desktop? | Yes |
96 | | easing | string | | |
97 | | fade | bool | Slides use fade for transition | Yes |
98 | | focusOnSelect | bool | Go to slide on click | Yes |
99 | | infinite | bool | should the gallery wrap around it's contents | Yes |
100 | | initialSlide | int | which item should be the first to be displayed | Yes |
101 | | lazyLoad | bool | Loads images or renders components on demands | Yes |
102 | | pauseOnHover | bool | prevents autoplay while hovering | Yes |
103 | | responsive | array | Array of objects in the form of `{ breakpoint: int, settings: { ... } }` The breakpoint _int_ is the `maxWidth` so the settings will be applied when resolution is below this value. Breakpoints in the array should be ordered from smalles to greatest. Use 'unslick' in place of the settings object to disable rendering the carousel at that breakpoint. Example: `[ { breakpoint: 768, settings: { slidesToShow: 3 } }, { breakpoint: 1024, settings: { slidesToShow: 5 } }, { breakpoint: 100000, settings: 'unslick' } ]`| Yes |
104 | | rtl | bool | Reverses the slide order | Yes |
105 | | slide | string |||
106 | | slidesToShow | int | Number of slides to be visible at a time | Yes |
107 | | slidesToScroll | int | Number of slides to scroll for each navigation item
108 | | speed | int |||
109 | | swipe | bool |||
110 | | swipeToSlide | bool | Allow users to drag or swipe directly to a slide irrespective of slidesToScroll | Yes |
111 | | touchMove | bool |||
112 | | touchThreshold | int |||
113 | | variableWidth | bool |||
114 | | useCSS | bool | Enable/Disable CSS Transitions | Yes |
115 | | vertical | bool | Vertical slide mode | Yes |
116 | | afterChange | function | callback function called after the current index changes | Yes |
117 | | beforeChange | function | callback function called before the current index changes | Yes |
118 | | slickGoTo | int | go to the specified slide number | |
119 |
120 |
121 | ### Methods
122 | * `slickNext()` - function called to change current slide on next slide ([Example](https://github.com/akiran/react-slick/blob/master/examples/PreviousNextMethods.js))
123 | * `slickPrev()` - function called to change current slide on previous slide ([Example](https://github.com/akiran/react-slick/blob/master/examples/PreviousNextMethods.js))
124 | * `slickGoTo(slideNumber)` - function called to change current slide to given slide number ([Example](https://github.com/akiran/react-slick/blob/master/examples/SlickGoTo.js))
125 |
126 | ### Custom next/prev arrows
127 |
128 | To customize the next/prev arrow elements, simply create new React components and set them
129 | as the values of nextArrow and prevArrow.
130 |
131 | ```js
132 | class LeftNavButton extends React.Component {
133 | render() {
134 | return
135 | }
136 | }
137 | ```
138 |
139 | Important: be sure that you pass your component's props to your clickable element
140 | like the example above. If you don't, your custom component won't trigger the click handler.
141 |
142 | You can also set `onClick={this.props.onClick}` if you only want to set the click handler.
143 |
144 | ### Flexbox support
145 | If you have flex property on container div of slider, add below css
146 | ```css
147 | * {
148 | min-height: 0;
149 | min-width: 0;
150 | }
151 | ```
152 |
153 | ### Test Setup
154 | If you try to run tests with jest in a project that uses react-slick, you my run into this error
155 | ```
156 | matchMedia not present, legacy browsers require a polyfill
157 | ```
158 |
159 | To fix this issue add below snippet in test-setup.js
160 | ```js
161 | window.matchMedia = window.matchMedia || function() {
162 | return {
163 | matches : false,
164 | addListener : function() {},
165 | removeListener: function() {}
166 | };
167 | };
168 |
169 | ```
170 | and add below jest config in package.json
171 | ```json
172 | "jest": {
173 | "setupFiles": ["test-setup.js"]
174 | }
175 | ```
176 |
177 |
178 | ### Development
179 | Want to run demos locally
180 |
181 | ```bash
182 | git clone https://github.com/akiran/react-slick
183 | npm install
184 | npm start
185 | open http://localhost:8080
186 | ```
187 |
188 | ### Polyfills for old IE support
189 | `matchMedia` support from [media-match](https://github.com/weblinc/media-match)
190 |
--------------------------------------------------------------------------------
/src/inner-slider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import EventHandlersMixin from './mixins/event-handlers';
5 | import HelpersMixin from './mixins/helpers';
6 | import initialState from './initial-state';
7 | import defaultProps from './default-props';
8 | import createReactClass from 'create-react-class';
9 | import classnames from 'classnames';
10 | import assign from 'object-assign';
11 |
12 | import {Track} from './track';
13 | import {Dots} from './dots';
14 | import {PrevArrow, NextArrow} from './arrows';
15 |
16 | export var InnerSlider = createReactClass({
17 | mixins: [HelpersMixin, EventHandlersMixin],
18 | list: null,
19 | track: null,
20 | listRefHandler: function (ref) {
21 | this.list = ref;
22 | },
23 | trackRefHandler: function (ref) {
24 | this.track = ref;
25 | },
26 | getInitialState: function () {
27 | return Object.assign({}, initialState, {
28 | currentSlide: this.props.initialSlide
29 | });
30 | },
31 | getDefaultProps: function () {
32 | return defaultProps;
33 | },
34 | componentWillMount: function () {
35 | if (this.props.init) {
36 | this.props.init();
37 | }
38 | this.setState({
39 | mounted: true
40 | });
41 | var lazyLoadedList = [];
42 | for (var i = 0; i < React.Children.count(this.props.children); i++) {
43 | if (i >= this.state.currentSlide && i < this.state.currentSlide + this.props.slidesToShow) {
44 | lazyLoadedList.push(i);
45 | }
46 | }
47 |
48 | if (this.props.lazyLoad && this.state.lazyLoadedList.length === 0) {
49 | this.setState({
50 | lazyLoadedList: lazyLoadedList
51 | });
52 | }
53 | },
54 | componentDidMount: function componentDidMount() {
55 | // Hack for autoplay -- Inspect Later
56 | this.initialize(this.props);
57 | this.adaptHeight();
58 |
59 | // To support server-side rendering
60 | if (!window) {
61 | return
62 | }
63 | if (window.addEventListener) {
64 | window.addEventListener('resize', this.onWindowResized);
65 | } else {
66 | window.attachEvent('onresize', this.onWindowResized);
67 | }
68 | },
69 | componentWillUnmount: function componentWillUnmount() {
70 | if (this.animationEndCallback) {
71 | clearTimeout(this.animationEndCallback);
72 | }
73 | if (window.addEventListener) {
74 | window.removeEventListener('resize', this.onWindowResized);
75 | } else {
76 | window.detachEvent('onresize', this.onWindowResized);
77 | }
78 | if (this.state.autoPlayTimer) {
79 | clearInterval(this.state.autoPlayTimer);
80 | }
81 | },
82 | componentWillReceiveProps: function(nextProps) {
83 | if (this.props.slickGoTo != nextProps.slickGoTo) {
84 | if (process.env.NODE_ENV !== 'production') {
85 | console.warn('react-slick deprecation warning: slickGoTo prop is deprecated and it will be removed in next release. Use slickGoTo method instead')
86 | }
87 | this.changeSlide({
88 | message: 'index',
89 | index: nextProps.slickGoTo,
90 | currentSlide: this.state.currentSlide
91 | });
92 | } else if (this.state.currentSlide >= nextProps.children.length) {
93 | this.update(nextProps);
94 | this.changeSlide({
95 | message: 'index',
96 | index: nextProps.children.length - nextProps.slidesToShow,
97 | currentSlide: this.state.currentSlide
98 | });
99 | } else {
100 | this.update(nextProps);
101 | }
102 | },
103 | componentDidUpdate: function () {
104 | this.adaptHeight();
105 | },
106 | onWindowResized: function () {
107 | this.update(this.props);
108 | // animating state should be cleared while resizing, otherwise autoplay stops working
109 | this.setState({
110 | animating: false
111 | });
112 | clearTimeout(this.animationEndCallback);
113 | delete this.animationEndCallback;
114 | },
115 | slickPrev: function () {
116 | this.changeSlide({message: 'previous'});
117 | },
118 | slickNext: function () {
119 | this.changeSlide({message: 'next'});
120 | },
121 | slickGoTo: function (slide) {
122 | typeof slide === 'number' && this.changeSlide({
123 | message: 'index',
124 | index: slide,
125 | currentSlide: this.state.currentSlide
126 | });
127 | },
128 | render: function () {
129 | var className = classnames('slick-initialized', 'slick-slider', this.props.className, {
130 | 'slick-vertical': this.props.vertical,
131 | });
132 |
133 | var trackProps = {
134 | fade: this.props.fade,
135 | cssEase: this.props.cssEase,
136 | speed: this.props.speed,
137 | infinite: this.props.infinite,
138 | centerMode: this.props.centerMode,
139 | focusOnSelect: this.props.focusOnSelect ? this.selectHandler : null,
140 | currentSlide: this.state.currentSlide,
141 | lazyLoad: this.props.lazyLoad,
142 | lazyLoadedList: this.state.lazyLoadedList,
143 | rtl: this.props.rtl,
144 | slideWidth: this.state.slideWidth,
145 | slidesToShow: this.props.slidesToShow,
146 | slidesToScroll: this.props.slidesToScroll,
147 | slideCount: this.state.slideCount,
148 | trackStyle: this.state.trackStyle,
149 | variableWidth: this.props.variableWidth
150 | };
151 |
152 | var dots;
153 |
154 | if (this.props.dots === true && this.state.slideCount >= this.props.slidesToShow) {
155 | var dotProps = {
156 | dotsClass: this.props.dotsClass,
157 | slideCount: this.state.slideCount,
158 | slidesToShow: this.props.slidesToShow,
159 | currentSlide: this.state.currentSlide,
160 | slidesToScroll: this.props.slidesToScroll,
161 | clickHandler: this.changeSlide,
162 | children: this.props.children,
163 | customPaging: this.props.customPaging
164 | };
165 |
166 | dots = ();
167 | }
168 |
169 | var prevArrow, nextArrow;
170 |
171 | var arrowProps = {
172 | infinite: this.props.infinite,
173 | centerMode: this.props.centerMode,
174 | currentSlide: this.state.currentSlide,
175 | slideCount: this.state.slideCount,
176 | slidesToShow: this.props.slidesToShow,
177 | prevArrow: this.props.prevArrow,
178 | nextArrow: this.props.nextArrow,
179 | clickHandler: this.changeSlide
180 | };
181 |
182 | if (this.props.arrows) {
183 | prevArrow = ();
184 | nextArrow = ();
185 | }
186 |
187 | var verticalHeightStyle = null;
188 |
189 | if (this.props.vertical) {
190 | verticalHeightStyle = {
191 | height: this.state.listHeight,
192 | };
193 | }
194 |
195 | var centerPaddingStyle = null;
196 |
197 | if (this.props.vertical === false) {
198 | if (this.props.centerMode === true) {
199 | centerPaddingStyle = {
200 | padding: ('0px ' + this.props.centerPadding)
201 | };
202 | }
203 | } else {
204 | if (this.props.centerMode === true) {
205 | centerPaddingStyle = {
206 | padding: (this.props.centerPadding + ' 0px')
207 | };
208 | }
209 | }
210 |
211 | const listStyle = assign({}, verticalHeightStyle, centerPaddingStyle);
212 |
213 | return (
214 |
220 | {prevArrow}
221 |
234 |
237 |
238 | {nextArrow}
239 | {dots}
240 |
241 | );
242 | }
243 | });
244 |
--------------------------------------------------------------------------------
/src/mixins/event-handlers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
3 | import helpers from './helpers';
4 | import assign from 'object-assign';
5 | import ReactDOM from 'react-dom';
6 |
7 | var EventHandlers = {
8 | // Event handler for previous and next
9 | changeSlide: function (options) {
10 | var indexOffset, previousInt, slideOffset, unevenOffset, targetSlide;
11 | const {slidesToScroll, slidesToShow} = this.props
12 | const {slideCount, currentSlide} = this.state
13 | unevenOffset = (slideCount % slidesToScroll !== 0);
14 | indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;
15 |
16 | if (options.message === 'previous') {
17 | slideOffset = (indexOffset === 0) ? slidesToScroll : slidesToShow - indexOffset;
18 | targetSlide = currentSlide - slideOffset;
19 | if (this.props.lazyLoad) {
20 | previousInt = currentSlide - slideOffset;
21 | targetSlide = previousInt === -1 ? slideCount -1 : previousInt;
22 | }
23 | } else if (options.message === 'next') {
24 | slideOffset = (indexOffset === 0) ? slidesToScroll : indexOffset;
25 | targetSlide = currentSlide + slideOffset;
26 | if (this.props.lazyLoad) {
27 | targetSlide = ((currentSlide + slidesToScroll) % slideCount) + indexOffset;
28 | }
29 | } else if (options.message === 'dots' || options.message === 'children') {
30 | // Click on dots
31 | targetSlide = options.index * options.slidesToScroll;
32 | if (targetSlide === options.currentSlide) {
33 | return;
34 | }
35 | } else if (options.message === 'index') {
36 | targetSlide = parseInt(options.index);
37 | if (targetSlide === options.currentSlide) {
38 | return;
39 | }
40 | }
41 |
42 | this.slideHandler(targetSlide);
43 | },
44 |
45 | // Accessiblity handler for previous and next
46 | keyHandler: function (e) {
47 | //Dont slide if the cursor is inside the form fields and arrow keys are pressed
48 | if(!e.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
49 | if (e.keyCode === 37 && this.props.accessibility === true) {
50 | this.changeSlide({
51 | message: this.props.rtl === true ? 'next' : 'previous'
52 | });
53 | } else if (e.keyCode === 39 && this.props.accessibility === true) {
54 | this.changeSlide({
55 | message: this.props.rtl === true ? 'previous' : 'next'
56 | });
57 | }
58 | }
59 | },
60 | // Focus on selecting a slide (click handler on track)
61 | selectHandler: function (options) {
62 | this.changeSlide(options)
63 | },
64 | swipeStart: function (e) {
65 | var touches, posX, posY;
66 |
67 | if ((this.props.swipe === false) || ('ontouchend' in document && this.props.swipe === false)) {
68 | return;
69 | } else if (this.props.draggable === false && e.type.indexOf('mouse') !== -1) {
70 | return;
71 | }
72 | posX = (e.touches !== undefined) ? e.touches[0].pageX : e.clientX;
73 | posY = (e.touches !== undefined) ? e.touches[0].pageY : e.clientY;
74 | this.setState({
75 | dragging: true,
76 | touchObject: {
77 | startX: posX,
78 | startY: posY,
79 | curX: posX,
80 | curY: posY
81 | }
82 | });
83 | },
84 | swipeMove: function (e) {
85 | if (!this.state.dragging) {
86 | e.preventDefault();
87 | return;
88 | }
89 | if (this.state.animating) {
90 | return;
91 | }
92 | if (this.props.vertical && this.props.swipeToSlide && this.props.verticalSwiping) {
93 | e.preventDefault();
94 | }
95 | var swipeLeft;
96 | var curLeft, positionOffset;
97 | var touchObject = this.state.touchObject;
98 |
99 | curLeft = getTrackLeft(assign({
100 | slideIndex: this.state.currentSlide,
101 | trackRef: this.track
102 | }, this.props, this.state));
103 | touchObject.curX = (e.touches) ? e.touches[0].pageX : e.clientX;
104 | touchObject.curY = (e.touches) ? e.touches[0].pageY : e.clientY;
105 | touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curX - touchObject.startX, 2)));
106 |
107 | if (this.props.verticalSwiping) {
108 | touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curY - touchObject.startY, 2)));
109 | }
110 |
111 | positionOffset = (this.props.rtl === false ? 1 : -1) * (touchObject.curX > touchObject.startX ? 1 : -1);
112 |
113 | if (this.props.verticalSwiping) {
114 | positionOffset = touchObject.curY > touchObject.startY ? 1 : -1;
115 | }
116 |
117 | var currentSlide = this.state.currentSlide;
118 | var dotCount = Math.ceil(this.state.slideCount / this.props.slidesToScroll);
119 | var swipeDirection = this.swipeDirection(this.state.touchObject);
120 | var touchSwipeLength = touchObject.swipeLength;
121 |
122 | if (this.props.infinite === false) {
123 | if ((currentSlide === 0 && swipeDirection === 'right') || (currentSlide + 1 >= dotCount && swipeDirection === 'left')) {
124 | touchSwipeLength = touchObject.swipeLength * this.props.edgeFriction;
125 |
126 | if (this.state.edgeDragged === false && this.props.edgeEvent) {
127 | this.props.edgeEvent(swipeDirection);
128 | this.setState({ edgeDragged: true });
129 | }
130 | }
131 | }
132 |
133 | if (this.state.swiped === false && this.props.swipeEvent) {
134 | this.props.swipeEvent(swipeDirection);
135 | this.setState({ swiped: true });
136 | }
137 |
138 | if (!this.props.vertical) {
139 | swipeLeft = curLeft + touchSwipeLength * positionOffset;
140 | } else {
141 | swipeLeft = curLeft + (touchSwipeLength * (this.state.listHeight / this.state.listWidth)) * positionOffset;
142 | }
143 |
144 | if (this.props.verticalSwiping) {
145 | swipeLeft = curLeft + touchSwipeLength * positionOffset;
146 | }
147 |
148 | this.setState({
149 | touchObject: touchObject,
150 | swipeLeft: swipeLeft,
151 | trackStyle: getTrackCSS(assign({left: swipeLeft}, this.props, this.state))
152 | });
153 |
154 | if (Math.abs(touchObject.curX - touchObject.startX) < Math.abs(touchObject.curY - touchObject.startY) * 0.8)
155 | { return; }
156 | if (touchObject.swipeLength > 4) {
157 | e.preventDefault();
158 | }
159 | },
160 | getNavigableIndexes() {
161 | let max;
162 | let breakPoint = 0;
163 | let counter = 0;
164 | let indexes = [];
165 |
166 | if (!this.props.infinite) {
167 | max = this.state.slideCount;
168 | } else {
169 | breakPoint = this.props.slidesToShow * -1;
170 | counter = this.props.slidesToShow * -1;
171 | max = this.state.slideCount * 2;
172 | }
173 |
174 | while (breakPoint < max) {
175 | indexes.push(breakPoint);
176 | breakPoint = counter + this.props.slidesToScroll;
177 |
178 | counter += this.props.slidesToScroll <= this.props.slidesToShow ?
179 | this.props.slidesToScroll : this.props.slidesToShow;
180 | }
181 |
182 | return indexes;
183 | },
184 | checkNavigable(index) {
185 | const navigables = this.getNavigableIndexes();
186 | let prevNavigable = 0;
187 |
188 | if (index > navigables[navigables.length - 1]) {
189 | index = navigables[navigables.length - 1];
190 | } else {
191 | for (var n in navigables) {
192 | if (index < navigables[n]) {
193 | index = prevNavigable;
194 | break;
195 | }
196 |
197 | prevNavigable = navigables[n];
198 | }
199 | }
200 |
201 | return index;
202 | },
203 | getSlideCount() {
204 | const centerOffset = this.props.centerMode ? this.state.slideWidth * Math.floor(this.props.slidesToShow / 2) : 0;
205 |
206 | if (this.props.swipeToSlide) {
207 | let swipedSlide;
208 |
209 | const slickList = ReactDOM.findDOMNode(this.list);
210 |
211 | const slides = slickList.querySelectorAll('.slick-slide');
212 |
213 | Array.from(slides).every((slide) => {
214 | if (!this.props.vertical) {
215 | if (slide.offsetLeft - centerOffset + (this.getWidth(slide) / 2) > this.state.swipeLeft * -1) {
216 | swipedSlide = slide;
217 | return false;
218 | }
219 | } else {
220 | if (slide.offsetTop + (this.getHeight(slide) / 2) > this.state.swipeLeft * -1) {
221 | swipedSlide = slide;
222 | return false;
223 | }
224 | }
225 |
226 | return true;
227 | });
228 |
229 | const slidesTraversed = Math.abs(swipedSlide.dataset.index - this.state.currentSlide) || 1;
230 |
231 | return slidesTraversed;
232 | } else {
233 | return this.props.slidesToScroll;
234 | }
235 | },
236 | swipeEnd: function (e) {
237 | if (!this.state.dragging) {
238 | if (this.props.swipe) {
239 | e.preventDefault();
240 | }
241 | return;
242 | }
243 | var touchObject = this.state.touchObject;
244 | var minSwipe = this.state.listWidth/this.props.touchThreshold;
245 | var swipeDirection = this.swipeDirection(touchObject);
246 |
247 | if (this.props.verticalSwiping) {
248 | minSwipe = this.state.listHeight/this.props.touchThreshold;
249 | }
250 |
251 | // reset the state of touch related state variables.
252 | this.setState({
253 | dragging: false,
254 | edgeDragged: false,
255 | swiped: false,
256 | swipeLeft: null,
257 | touchObject: {}
258 | });
259 | // Fix for #13
260 | if (!touchObject.swipeLength) {
261 | return;
262 | }
263 | if (touchObject.swipeLength > minSwipe) {
264 | e.preventDefault();
265 |
266 | let slideCount, newSlide;
267 |
268 | switch (swipeDirection) {
269 |
270 | case 'left':
271 | case 'down':
272 | newSlide = this.state.currentSlide + this.getSlideCount();
273 | slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
274 | this.state.currentDirection = 0;
275 | break;
276 |
277 | case 'right':
278 | case 'up':
279 | newSlide = this.state.currentSlide - this.getSlideCount();
280 | slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
281 | this.state.currentDirection = 1;
282 | break;
283 |
284 | default:
285 | slideCount = this.state.currentSlide;
286 |
287 | }
288 |
289 | this.slideHandler(slideCount);
290 | } else {
291 | // Adjust the track back to it's original position.
292 | var currentLeft = getTrackLeft(assign({
293 | slideIndex: this.state.currentSlide,
294 | trackRef: this.track
295 | }, this.props, this.state));
296 |
297 | this.setState({
298 | trackStyle: getTrackAnimateCSS(assign({left: currentLeft}, this.props, this.state))
299 | });
300 | }
301 | },
302 | onInnerSliderEnter: function (e) {
303 | if (this.props.autoplay && this.props.pauseOnHover) {
304 | this.pause();
305 | }
306 | },
307 | onInnerSliderOver: function (e) {
308 | if (this.props.autoplay && this.props.pauseOnHover) {
309 | this.pause();
310 | }
311 | },
312 | onInnerSliderLeave: function (e) {
313 | if (this.props.autoplay && this.props.pauseOnHover) {
314 | this.autoPlay();
315 | }
316 | }
317 | };
318 |
319 | export default EventHandlers;
320 |
--------------------------------------------------------------------------------
/src/mixins/helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React from 'react';
4 | import ReactDOM from 'react-dom';
5 | import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
6 | import assign from 'object-assign';
7 |
8 | var helpers = {
9 | initialize: function (props) {
10 | const slickList = ReactDOM.findDOMNode(this.list);
11 |
12 | var slideCount = React.Children.count(props.children);
13 | var listWidth = this.getWidth(slickList);
14 | var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
15 | var slideWidth;
16 |
17 | if (!props.vertical) {
18 | var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
19 | slideWidth = (this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow;
20 | } else {
21 | slideWidth = this.getWidth(ReactDOM.findDOMNode(this));
22 | }
23 |
24 | const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
25 | const listHeight = slideHeight * props.slidesToShow;
26 |
27 | var currentSlide = props.rtl ? slideCount - 1 - props.initialSlide : props.initialSlide;
28 |
29 | this.setState({
30 | slideCount,
31 | slideWidth,
32 | listWidth,
33 | trackWidth,
34 | currentSlide,
35 | slideHeight,
36 | listHeight,
37 | }, function () {
38 |
39 | var targetLeft = getTrackLeft(assign({
40 | slideIndex: this.state.currentSlide,
41 | trackRef: this.track
42 | }, props, this.state));
43 | // getCSS function needs previously set state
44 | var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));
45 |
46 | this.setState({trackStyle: trackStyle});
47 |
48 | this.autoPlay(); // once we're set up, trigger the initial autoplay.
49 | });
50 | },
51 | update: function (props) {
52 | const slickList = ReactDOM.findDOMNode(this.list);
53 | // This method has mostly same code as initialize method.
54 | // Refactor it
55 | var slideCount = React.Children.count(props.children);
56 | var listWidth = this.getWidth(slickList);
57 | var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
58 | var slideWidth;
59 |
60 | if (!props.vertical) {
61 | var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
62 | slideWidth = (this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow;
63 | } else {
64 | slideWidth = this.getWidth(ReactDOM.findDOMNode(this));
65 | }
66 |
67 | const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
68 | const listHeight = slideHeight * props.slidesToShow;
69 |
70 | // pause slider if autoplay is set to false
71 | if(props.autoplay) {
72 | this.pause();
73 | } else {
74 | this.autoPlay();
75 | }
76 |
77 | this.setState({
78 | slideCount,
79 | slideWidth,
80 | listWidth,
81 | trackWidth,
82 | slideHeight,
83 | listHeight,
84 | }, function () {
85 |
86 | var targetLeft = getTrackLeft(assign({
87 | slideIndex: this.state.currentSlide,
88 | trackRef: this.track
89 | }, props, this.state));
90 | // getCSS function needs previously set state
91 | var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));
92 |
93 | this.setState({trackStyle: trackStyle});
94 | });
95 | },
96 | getWidth: function getWidth(elem) {
97 | return elem.getBoundingClientRect().width || elem.offsetWidth || 0;
98 | },
99 | getHeight(elem) {
100 | return elem.getBoundingClientRect().height || elem.offsetHeight || 0;
101 | },
102 | adaptHeight: function () {
103 | if (this.props.adaptiveHeight) {
104 | var selector = '[data-index="' + this.state.currentSlide +'"]';
105 | if (this.list) {
106 | var slickList = ReactDOM.findDOMNode(this.list);
107 | slickList.style.height = slickList.querySelector(selector).offsetHeight + 'px';
108 | }
109 | }
110 | },
111 | canGoNext: function (opts){
112 | var canGo = true;
113 | if (!opts.infinite) {
114 | if (opts.centerMode) {
115 | // check if current slide is last slide
116 | if (opts.currentSlide >= (opts.slideCount - 1)) {
117 | canGo = false;
118 | }
119 | } else {
120 | // check if all slides are shown in slider
121 | if (opts.slideCount <= opts.slidesToShow ||
122 | opts.currentSlide >= (opts.slideCount - opts.slidesToShow)) {
123 | canGo = false;
124 | }
125 | }
126 | }
127 | return canGo;
128 | },
129 | slideHandler: function (index) {
130 | // Functionality of animateSlide and postSlide is merged into this function
131 | // console.log('slideHandler', index);
132 | var targetSlide, currentSlide;
133 | var targetLeft, currentLeft;
134 | var callback;
135 |
136 | if (this.props.waitForAnimate && this.state.animating) {
137 | return;
138 | }
139 |
140 | if (this.props.fade) {
141 | currentSlide = this.state.currentSlide;
142 |
143 | // Don't change slide if it's not infite and current slide is the first or last slide.
144 | if(this.props.infinite === false &&
145 | (index < 0 || index >= this.state.slideCount)) {
146 | return;
147 | }
148 |
149 | // Shifting targetSlide back into the range
150 | if (index < 0) {
151 | targetSlide = index + this.state.slideCount;
152 | } else if (index >= this.state.slideCount) {
153 | targetSlide = index - this.state.slideCount;
154 | } else {
155 | targetSlide = index;
156 | }
157 |
158 | if (this.props.lazyLoad && this.state.lazyLoadedList.indexOf(targetSlide) < 0) {
159 | this.setState({
160 | lazyLoadedList: this.state.lazyLoadedList.concat(targetSlide)
161 | });
162 | }
163 |
164 | callback = () => {
165 | this.setState({
166 | animating: false
167 | });
168 | if (this.props.afterChange) {
169 | this.props.afterChange(targetSlide);
170 | }
171 | delete this.animationEndCallback;
172 | };
173 |
174 | this.setState({
175 | animating: true,
176 | currentSlide: targetSlide
177 | }, function () {
178 | this.animationEndCallback = setTimeout(callback, this.props.speed);
179 | });
180 |
181 | if (this.props.beforeChange) {
182 | this.props.beforeChange(this.state.currentSlide, targetSlide);
183 | }
184 |
185 | this.autoPlay();
186 | return;
187 | }
188 |
189 | targetSlide = index;
190 | if (targetSlide < 0) {
191 | if(this.props.infinite === false) {
192 | currentSlide = 0;
193 | } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
194 | currentSlide = this.state.slideCount - (this.state.slideCount % this.props.slidesToScroll);
195 | } else {
196 | currentSlide = this.state.slideCount + targetSlide;
197 | }
198 | } else if (targetSlide >= this.state.slideCount) {
199 | if(this.props.infinite === false) {
200 | currentSlide = this.state.slideCount - this.props.slidesToShow;
201 | } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
202 | currentSlide = 0;
203 | } else {
204 | currentSlide = targetSlide - this.state.slideCount;
205 | }
206 | } else {
207 | currentSlide = targetSlide;
208 | }
209 |
210 | targetLeft = getTrackLeft(assign({
211 | slideIndex: targetSlide,
212 | trackRef: this.track
213 | }, this.props, this.state));
214 |
215 | currentLeft = getTrackLeft(assign({
216 | slideIndex: currentSlide,
217 | trackRef: this.track
218 | }, this.props, this.state));
219 |
220 | if (this.props.infinite === false) {
221 | targetLeft = currentLeft;
222 | }
223 |
224 | if (this.props.beforeChange) {
225 | this.props.beforeChange(this.state.currentSlide, currentSlide);
226 | }
227 |
228 | if (this.props.lazyLoad) {
229 | var loaded = true;
230 | var slidesToLoad = [];
231 | for (var i = targetSlide; i < targetSlide + this.props.slidesToShow; i++ ) {
232 | loaded = loaded && (this.state.lazyLoadedList.indexOf(i) >= 0);
233 | if (!loaded) {
234 | slidesToLoad.push(i);
235 | }
236 | }
237 | if (!loaded) {
238 | this.setState({
239 | lazyLoadedList: this.state.lazyLoadedList.concat(slidesToLoad)
240 | });
241 | }
242 | }
243 |
244 | // Slide Transition happens here.
245 | // animated transition happens to target Slide and
246 | // non - animated transition happens to current Slide
247 | // If CSS transitions are false, directly go the current slide.
248 |
249 | if (this.props.useCSS === false) {
250 |
251 | this.setState({
252 | currentSlide: currentSlide,
253 | trackStyle: getTrackCSS(assign({left: currentLeft}, this.props, this.state))
254 | }, function () {
255 | if (this.props.afterChange) {
256 | this.props.afterChange(currentSlide);
257 | }
258 | });
259 |
260 | } else {
261 |
262 | var nextStateChanges = {
263 | animating: false,
264 | currentSlide: currentSlide,
265 | trackStyle: getTrackCSS(assign({left: currentLeft}, this.props, this.state)),
266 | swipeLeft: null
267 | };
268 |
269 | callback = () => {
270 | this.setState(nextStateChanges);
271 | if (this.props.afterChange) {
272 | this.props.afterChange(currentSlide);
273 | }
274 | delete this.animationEndCallback;
275 | };
276 |
277 | this.setState({
278 | animating: true,
279 | currentSlide: currentSlide,
280 | trackStyle: getTrackAnimateCSS(assign({left: targetLeft}, this.props, this.state))
281 | }, function () {
282 | this.animationEndCallback = setTimeout(callback, this.props.speed);
283 | });
284 |
285 | }
286 |
287 | this.autoPlay();
288 | },
289 | swipeDirection: function (touchObject) {
290 | var xDist, yDist, r, swipeAngle;
291 |
292 | xDist = touchObject.startX - touchObject.curX;
293 | yDist = touchObject.startY - touchObject.curY;
294 | r = Math.atan2(yDist, xDist);
295 |
296 | swipeAngle = Math.round(r * 180 / Math.PI);
297 | if (swipeAngle < 0) {
298 | swipeAngle = 360 - Math.abs(swipeAngle);
299 | }
300 | if ((swipeAngle <= 45) && (swipeAngle >= 0) || (swipeAngle <= 360) && (swipeAngle >= 315)) {
301 | return (this.props.rtl === false ? 'left' : 'right');
302 | }
303 | if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
304 | return (this.props.rtl === false ? 'right' : 'left');
305 | }
306 | if (this.props.verticalSwiping === true) {
307 | if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
308 | return 'down';
309 | } else {
310 | return 'up';
311 | }
312 | }
313 |
314 | return 'vertical';
315 | },
316 | play: function(){
317 | var nextIndex;
318 |
319 | if (!this.state.mounted) {
320 | return false
321 | }
322 |
323 | if (this.props.rtl) {
324 | nextIndex = this.state.currentSlide - this.props.slidesToScroll;
325 | } else {
326 | if (this.canGoNext(Object.assign({}, this.props,this.state))) {
327 | nextIndex = this.state.currentSlide + this.props.slidesToScroll;
328 | } else {
329 | return false;
330 | }
331 | }
332 |
333 | this.slideHandler(nextIndex);
334 | },
335 | autoPlay: function () {
336 | if (this.state.autoPlayTimer) {
337 | clearTimeout(this.state.autoPlayTimer);
338 | }
339 | if (this.props.autoplay) {
340 | this.setState({
341 | autoPlayTimer: setTimeout(this.play, this.props.autoplaySpeed)
342 | });
343 | }
344 | },
345 | pause: function () {
346 | if (this.state.autoPlayTimer) {
347 | clearTimeout(this.state.autoPlayTimer);
348 | this.setState({
349 | autoPlayTimer: null
350 | });
351 | }
352 | }
353 | };
354 |
355 | export default helpers;
356 |
--------------------------------------------------------------------------------