├── .gitignore ├── README.md ├── dist ├── deck3000.css ├── deck3000.es.js ├── deck3000.js ├── deck3000.min.css └── deck3000.umd.js ├── docs ├── index.html ├── src.461479b2.js └── style.499f78c8.css ├── package.json └── src ├── Emitter.js ├── MouseWheel.js ├── Section.js ├── SetBrowserHistory.js ├── SetCurrentState.js ├── SetPosition.js ├── Slide.js ├── ToSlug.js ├── ToggleClass.js ├── TouchEvents.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | .npmignore 3 | *.lock 4 | *.map 5 | node_modules 6 | *.log 7 | docs/deck3000.es.js 8 | docs/deck3000.js 9 | docs/src 10 | .cache 11 | dev -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![alt text](https://image.ibb.co/diKhV8/deck3k.png "Deck3000") 2 | 3 | **A slider component for the new millennium.** 4 | 5 | ## What it is 6 | Simple! It's a slider component 😀 which can navigate (infinitely!) vertically ("sections") and horizontally ("slides", within a current section) in pure javascript. 7 | 8 | What this component provides is a way to handle the basic and essential interactions of the slider itself. This will not provide you with the UI or anything like that; all the fun and responsibility of implementing the UI and interaction around the slider is all up to you! 9 | 10 | ![alt text](https://s22.postimg.cc/bus8dzp41/ezgif-1-7c340b3d99.gif "Deck3000 simple sample") 11 | 12 | ## Features 13 | - Weighing in at a cute `~2kb` (js) `450b` (css) 14 | - Infinite slides (vertical / horizontal) 15 | - Scroll/Keyboard/Touch friendly 16 | - Super smooth 17 | - Super simple 18 | - Super cute 19 | 20 | ## Coming soon 21 | - [x] Navigation updates URL and history (replaceState) 22 | 23 | 24 | ## Getting Started 25 | 26 | Include the module via `npm i deck3000` or `yarn add deck3000` and import it into your project. 27 | 28 | ```js 29 | import Deck3000 from 'deck3000'; 30 | ``` 31 | 32 | **Very important** You must also include the [css](https://github.com/ezekielaquino/Deck3000/blob/master/dist/deck3000.css) that comes with the module! 33 | 34 | ```css 35 | // stylus, sass, etc. 36 | @import 'deck3000/dist/deck3000.css'; 37 | ``` 38 | 39 | ### DOM Structure 40 | **Deck3000** requires the following structure from your HTML (see below) 41 | - a parent container that includes the selector `js-deck3000` 42 | - sections must be a direct descendant of the parent container 43 | - slides must be a direct descendant of a section 44 | 45 | *Note*: if you plan on having elements that are siblings of a slide within a section (for example,some absolute positioned elements within a section) you *MUST* have a selector on each slide and declare that as a `slideSelector` option when instantiating **Deck3000**, otherwise *all* direct descendants of a section will be instantiated as a slide. 46 | 47 | After **Deck3000** successfully instantiated, a `is-init` selector will be attached to the parent `js-deck3000` element. 48 | 49 | Animation speed and easing are all done via [CSS](https://github.com/ezekielaquino/Deck3000/blob/5ac9c62b4b78e2b2ec27a05f45533c58dca27cb2/dist/deck3000.css#L21) in addition to all the essentials of making the component work so **don't forget to import the stylesheet!** 50 | 51 | ```html 52 |
53 | 54 |
55 |
56 | Slide one 57 |
58 |
59 | Slide two 60 |
61 |
62 | Slide three 63 |
64 |
65 | 66 | 67 |
68 |
69 | Section two - Slide one 70 |
71 |
72 | Section two - Slide two 73 |
74 |
75 | Section two - Slide three 76 |
77 |
78 |
79 | ``` 80 | 81 | ```js 82 | const Slideshow = new Deck3000({ 83 | slideSelector: '.slide', // (optional) 84 | resetSlides: true, 85 | keyboardEvents: true, 86 | updateURL: true, 87 | onInit: state => func, 88 | onSectionStart: state => onSectionStart, 89 | onSectionEnd: state => func, 90 | onSlideStart: state => func, 91 | onSlideEnd: state => func, 92 | }); 93 | 94 | const onSectionStart = state => { 95 | console.log(state); // This logs the state object below 96 | }; 97 | ``` 98 | 99 | **Callbacks exposes `state`** 100 | ```js 101 | { 102 | currentSectionElem: DOMNode, // current section 103 | currentSlideElem: DOMNode, // currentSlide, 104 | section: { 105 | current: 1, 106 | direction: 'next', 107 | isAnimating: false, 108 | next: 2, 109 | prev: 0, 110 | sectionLength: 3, // This is actually length - 1 111 | }, 112 | slide: { 113 | currentSlide: 0, 114 | next: 1, 115 | prev: 2, 116 | slideLength: 2, // This is actually length - 1 117 | } 118 | } 119 | ``` 120 | 121 | After **Deck3000** instantiates, it will not mutate the structure of the DOM in any way aside from adding classes to `sections` and `slides`. 122 | 123 | ## URLs 124 | 125 | If you have set `updateURL` to `true` then you may attach a `data-title="Whatever"` to a `section`. This string will be converted into a slug e.g. `Fashion brand` -> `fashion-brand` and will be appended to the URL `/fashion-brand` when you navigate across sections. If you do set `updateURL` to `true` but do *not* attach a data-title attribute, then it will just use the index of the current section e.g. `/0`. 126 | 127 | ## API 128 | 129 | #### navigate('type', 'direction') | Navigate through sections/slides. 130 | 131 | a.k.a The ✨🥩 of **Deck3000** 132 | 133 | `[Deck3000Instance].navigate(['section'/'slide'], ['next'/'prev']);` 134 | 135 | ```js 136 | const nextSlideBtn = document.querySelector('.nextSlideBtn'); 137 | 138 | nextSlideBtn.addEventListener('click', () => { 139 | Slideshow.navigate('slide', 'next'); 140 | }); 141 | ``` 142 | 143 | #### disableEvents(bool) | Toggles all (scroll/keyboard/swipe) events. 144 | 145 | `[Deck3000Instance].disableEvents(bool);` 146 | 147 | 148 | ```js 149 | // One might want to disable scroll events 150 | // (for ultimate peace of mind) 151 | // during certain UI states of your site/application 152 | const toggleOverlay = bool => { 153 | if (bool) { 154 | overlay.classList.add('is-active'); 155 | Slideshow.disableEvents(bool); 156 | return; 157 | } 158 | 159 | overlay.classList.remove('is-active'); 160 | }; 161 | ``` 162 | 163 | #### Emitter 164 | **Deck3000** uses `mitt` for handling events. The Emitter is exposed so you can subscribe to `navigate` (section) and `navigateSlide` (slide) events if you wish. 165 | 166 | ```js 167 | [Deck3000Instance].Emitter.on('navigate', e => { 168 | // Do something when navigating sections 169 | console.log(e); 170 | }); 171 | 172 | [Deck3000Instance].Emitter.on('navigateSlide', e=> { 173 | // Do something when navigating slides 174 | console.log(e); 175 | }); 176 | ``` 177 | 178 | ## Thanks 179 | - Built with [Microbundle](https://github.com/developit/microbundle) **It's awesome** 💃 180 | - Also built with [Parcel](https://parceljs.org/) 🕺 181 | 182 | ## License 183 | [MIT](https://oss.ninja/mit) 184 | -------------------------------------------------------------------------------- /dist/deck3000.css: -------------------------------------------------------------------------------- 1 | .js-deck3000 { 2 | width: 100vw; 3 | height: 100%; 4 | position: fixed; 5 | top: 0; 6 | left: 0; 7 | overflow: hidden; 8 | } 9 | 10 | .js-deck3000__section, 11 | .js-deck3000__section-slide { 12 | width: 100%; 13 | height: 100%; 14 | position: absolute; 15 | overflow: hidden; 16 | } 17 | 18 | .is-init .js-deck3000__section, 19 | .is-init .js-deck3000__section-slide { 20 | transition-property: transform; 21 | transition-duration: 0.5s; 22 | } 23 | 24 | .js-deck3000__section-slide { 25 | top: 0; 26 | } 27 | 28 | .js-deck3000__section.is-current, 29 | .js-deck3000__section-slide.is-current { 30 | top: 0; 31 | left: 0; 32 | transform: translate3d(0, 0, 0); 33 | } 34 | 35 | .js-deck3000__section.is-next { 36 | transform: translate3d(0, 100%, 0); 37 | } 38 | 39 | .js-deck3000__section.is-prev { 40 | transform: translate3d(0, -100%, 0); 41 | } 42 | 43 | .js-deck3000__section.is-instant, 44 | .js-deck3000__section-slide.is-instant { 45 | transition: none; 46 | } 47 | 48 | .js-deck3000__section-slide.is-next { 49 | transform: translate3d(100%, 0, 0); 50 | } 51 | 52 | .js-deck3000__section-slide.is-prev { 53 | transform: translate3d(-100%, 0, 0); 54 | } -------------------------------------------------------------------------------- /dist/deck3000.es.js: -------------------------------------------------------------------------------- 1 | var t,e=(t=t||Object.create(null),{on:function(e,i){(t[e]||(t[e]=[])).push(i)},off:function(e,i){t[e]&&t[e].splice(t[e].indexOf(i)>>>0,1)},emit:function(e,i){(t[e]||[]).slice().map(function(t){t(i)}),(t["*"]||[]).slice().map(function(t){t(e,i)})}}),i=function(t,e){var i;t.index===e.current?i="current":t.index===e.next?i="next":t.index===e.prev?i="prev":t.index>e.current?i="next":t.index0?"next":"prev",s=Math.sign(t.detail||t.deltaX)>0?"next":"prev";if(e.prevTime=e.currentTime,!e.state.isAnimating&&i>80){var a=2===t.axis||Math.abs(t.deltaY)&&Math.abs(t.deltaX)<=1,r=1===t.axis||Math.abs(t.deltaX)&&Math.abs(t.deltaY)<=1;if(a)return e.navigate("section",n);if(r)return e.navigate("slide",s)}},o=function(t){return void 0===t&&(t=""),t.split(" ").join("-").toLowerCase()},c=function(t){Object.assign(this,t),this.baseSelector="js-deck3000",this.element=document.querySelector("."+this.baseSelector),this.emitter=e,this.state={current:0,next:1},this.init(),this._onTransitionEnd=this._onTransitionEnd.bind(this)};c.prototype.init=function(){var t=this,i=this.state.current,n=Array.from(this.element.children).map(function(e,i,n){var r=window.location.pathname.split("/")[1];return t.state.sectionLength=t.state.prev=n.length-1,t.updateURL&&r&&(r!==o(e.dataset.title)&&r!==i.toString()||a({state:t.state,currentKey:"current",currentIndex:i,length:t.state.sectionLength,direction:i})),new s({slideshow:t,slideSelector:t.slideSelector,element:e,index:i})});this.sections=n,e.emit("navigate",this.state),e.emit("navigateSlide",{current:i}),setTimeout(function(){t.element.classList.add("is-init"),t.transitionDuration=1e3*parseFloat(getComputedStyle(t.sections[0].element).transitionDuration),t._attachEventHandlers(),t.onInit&&t.onInit(t._getCallbackState())},0)},c.prototype._attachEventHandlers=function(){var t,e,i,n,s,a=this;this.scrolls=[],this.prevTime=(new Date).getTime(),this.element.addEventListener("mousewheel",function(t){r(t,a)}),this.element.addEventListener("DOMMouseScroll",function(t){r(t,a)}),t=this,e=0,i=0,n=0,s=0,("ontouchstart"in window||navigator.msMaxTouchPoints>0||navigator.maxTouchPoints)&&(t.element.addEventListener("touchstart",function(t){e=t.changedTouches[0].screenX,i=t.changedTouches[0].screenY},!1),t.element.addEventListener("touchend",function(a){n=a.changedTouches[0].screenX,s=a.changedTouches[0].screenY;var r=Math.abs(n-e)>=100,o=Math.abs(s-i)>=100;return n<=e&&r?t.navigate("slide","next"):n>=e&&r?t.navigate("slide","prev"):s>=i&&o?t.navigate("section","prev"):s<=i&&o?t.navigate("section","next"):void 0},!1)),this.keyboardEvents&&window.addEventListener("keyup",function(t){if(!a.noEvents&&!a.state.isAnimating)switch(t.keyCode){case 38:a.navigate("section","prev");break;case 40:a.navigate("section","next");break;case 37:a.navigate("slide","prev");break;case 39:a.navigate("slide","next")}})},c.prototype.disableEvents=function(t){this.noEvents=t},c.prototype.navigate=function(t,i,n,s){var r=this;if(!this.noEvents&&!this.state.isAnimating){var c=this.state,l=c.current,h=c.sectionLength,d=this.sections[l],u="section"===t,v=u?d.element:d.slides[d.state.currentSlide].element,m=u?this.onSectionStart:this.onSlideStart,p=u?this.onSectionEnd:this.onSlideEnd;if(this.state.isAnimating=!n,this.state.direction=i,u)a({state:this.state,currentKey:"current",currentIndex:l,length:h,direction:i}),this.updateURL&&!n&&function(t,e){var i=o((e||t.current).toString());history.replaceState(t,e,i)}(this.state,this.sections[this.state.current].element.dataset.title),e.emit("navigate",this.state);else{var g=d,f=g.state,S=f.currentSlide,x=f.slideLength;n&&(g=this._getNextSection(s)),a({state:g.state,currentKey:"currentSlide",currentIndex:S,length:x,direction:i}),e.emit("navigateSlide",{current:l,direction:i,reset:n})}n||(m&&m(this._getCallbackState()),clearTimeout(this.timeout),this.timeout=setTimeout(function(){r._onTransitionEnd({element:v,onEnd:p,isSection:u,direction:i})},n?0:this.transitionDuration))}},c.prototype._getCallbackState=function(){var t=this.sections[this.state.current];return{section:this.state,slide:t.state,currentSectionElem:t.element,currentSlideElem:t.getCurrentSlide()}},c.prototype._getNextSection=function(t){var e=this.state;return"next"===t?this.sections[e.prev]:this.sections[e.next]},c.prototype._onTransitionEnd=function(t){var e=t.onEnd,i=t.isSection,n=t.direction;this.state.isAnimating=!1,i&&this.resetSlides&&this.navigate("slide",0,!0,n),e&&t.onEnd(this._getCallbackState())};export default c; 2 | //# sourceMappingURL=deck3000.es.js.map 3 | -------------------------------------------------------------------------------- /dist/deck3000.js: -------------------------------------------------------------------------------- 1 | "use strict";var t,e=(t=t||Object.create(null),{on:function(e,i){(t[e]||(t[e]=[])).push(i)},off:function(e,i){t[e]&&t[e].splice(t[e].indexOf(i)>>>0,1)},emit:function(e,i){(t[e]||[]).slice().map(function(t){t(i)}),(t["*"]||[]).slice().map(function(t){t(e,i)})}}),i=function(t,e){var i;t.index===e.current?i="current":t.index===e.next?i="next":t.index===e.prev?i="prev":t.index>e.current?i="next":t.index0?"next":"prev",s=Math.sign(t.detail||t.deltaX)>0?"next":"prev";if(e.prevTime=e.currentTime,!e.state.isAnimating&&i>80){var a=2===t.axis||Math.abs(t.deltaY)&&Math.abs(t.deltaX)<=1,r=1===t.axis||Math.abs(t.deltaX)&&Math.abs(t.deltaY)<=1;if(a)return e.navigate("section",n);if(r)return e.navigate("slide",s)}},o=function(t){return void 0===t&&(t=""),t.split(" ").join("-").toLowerCase()},c=function(t){Object.assign(this,t),this.baseSelector="js-deck3000",this.element=document.querySelector("."+this.baseSelector),this.emitter=e,this.state={current:0,next:1},this.init(),this._onTransitionEnd=this._onTransitionEnd.bind(this)};c.prototype.init=function(){var t=this,i=this.state.current,n=Array.from(this.element.children).map(function(e,i,n){var r=window.location.pathname.split("/")[1];return t.state.sectionLength=t.state.prev=n.length-1,t.updateURL&&r&&(r!==o(e.dataset.title)&&r!==i.toString()||a({state:t.state,currentKey:"current",currentIndex:i,length:t.state.sectionLength,direction:i})),new s({slideshow:t,slideSelector:t.slideSelector,element:e,index:i})});this.sections=n,e.emit("navigate",this.state),e.emit("navigateSlide",{current:i}),setTimeout(function(){t.element.classList.add("is-init"),t.transitionDuration=1e3*parseFloat(getComputedStyle(t.sections[0].element).transitionDuration),t._attachEventHandlers(),t.onInit&&t.onInit(t._getCallbackState())},0)},c.prototype._attachEventHandlers=function(){var t,e,i,n,s,a=this;this.scrolls=[],this.prevTime=(new Date).getTime(),this.element.addEventListener("mousewheel",function(t){r(t,a)}),this.element.addEventListener("DOMMouseScroll",function(t){r(t,a)}),t=this,e=0,i=0,n=0,s=0,("ontouchstart"in window||navigator.msMaxTouchPoints>0||navigator.maxTouchPoints)&&(t.element.addEventListener("touchstart",function(t){e=t.changedTouches[0].screenX,i=t.changedTouches[0].screenY},!1),t.element.addEventListener("touchend",function(a){n=a.changedTouches[0].screenX,s=a.changedTouches[0].screenY;var r=Math.abs(n-e)>=100,o=Math.abs(s-i)>=100;return n<=e&&r?t.navigate("slide","next"):n>=e&&r?t.navigate("slide","prev"):s>=i&&o?t.navigate("section","prev"):s<=i&&o?t.navigate("section","next"):void 0},!1)),this.keyboardEvents&&window.addEventListener("keyup",function(t){if(!a.noEvents&&!a.state.isAnimating)switch(t.keyCode){case 38:a.navigate("section","prev");break;case 40:a.navigate("section","next");break;case 37:a.navigate("slide","prev");break;case 39:a.navigate("slide","next")}})},c.prototype.disableEvents=function(t){this.noEvents=t},c.prototype.navigate=function(t,i,n,s){var r=this;if(!this.noEvents&&!this.state.isAnimating){var c=this.state,l=c.current,h=c.sectionLength,d=this.sections[l],u="section"===t,v=u?d.element:d.slides[d.state.currentSlide].element,m=u?this.onSectionStart:this.onSlideStart,p=u?this.onSectionEnd:this.onSlideEnd;if(this.state.isAnimating=!n,this.state.direction=i,u)a({state:this.state,currentKey:"current",currentIndex:l,length:h,direction:i}),this.updateURL&&!n&&function(t,e){var i=o((e||t.current).toString());history.replaceState(t,e,i)}(this.state,this.sections[this.state.current].element.dataset.title),e.emit("navigate",this.state);else{var g=d,f=g.state,S=f.currentSlide,x=f.slideLength;n&&(g=this._getNextSection(s)),a({state:g.state,currentKey:"currentSlide",currentIndex:S,length:x,direction:i}),e.emit("navigateSlide",{current:l,direction:i,reset:n})}n||(m&&m(this._getCallbackState()),clearTimeout(this.timeout),this.timeout=setTimeout(function(){r._onTransitionEnd({element:v,onEnd:p,isSection:u,direction:i})},n?0:this.transitionDuration))}},c.prototype._getCallbackState=function(){var t=this.sections[this.state.current];return{section:this.state,slide:t.state,currentSectionElem:t.element,currentSlideElem:t.getCurrentSlide()}},c.prototype._getNextSection=function(t){var e=this.state;return"next"===t?this.sections[e.prev]:this.sections[e.next]},c.prototype._onTransitionEnd=function(t){var e=t.onEnd,i=t.isSection,n=t.direction;this.state.isAnimating=!1,i&&this.resetSlides&&this.navigate("slide",0,!0,n),e&&t.onEnd(this._getCallbackState())},module.exports=c; 2 | //# sourceMappingURL=deck3000.js.map 3 | -------------------------------------------------------------------------------- /dist/deck3000.min.css: -------------------------------------------------------------------------------- 1 | .js-deck3000{width:100vw;height:100%;position:fixed;top:0;left:0;overflow:hidden}.js-deck3000__section,.js-deck3000__section-slide{width:100%;height:100%;position:absolute;overflow:hidden}.is-init .js-deck3000__section,.is-init .js-deck3000__section-slide{transition-property:transform;transition-duration:.35s}.js-deck3000__section-slide{top:0}.js-deck3000__section-slide.is-current,.js-deck3000__section.is-current{top:0;left:0;transform:translate3d(0,0,0)}.js-deck3000__section.is-next{transform:translate3d(0,100%,0)}.js-deck3000__section.is-prev{transform:translate3d(0,-100%,0)}.js-deck3000__section-slide.is-instant,.js-deck3000__section.is-instant{transition:none}.js-deck3000__section-slide.is-next{transform:translate3d(100%,0,0)}.js-deck3000__section-slide.is-prev{transform:translate3d(-100%,0,0)} -------------------------------------------------------------------------------- /dist/deck3000.umd.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Deck3000=e()}(this,function(){"use strict";var t,e=(t=t||Object.create(null),{on:function(e,i){(t[e]||(t[e]=[])).push(i)},off:function(e,i){t[e]&&t[e].splice(t[e].indexOf(i)>>>0,1)},emit:function(e,i){(t[e]||[]).slice().map(function(t){t(i)}),(t["*"]||[]).slice().map(function(t){t(e,i)})}}),i=function(t,e){var i;t.index===e.current?i="current":t.index===e.next?i="next":t.index===e.prev?i="prev":t.index>e.current?i="next":t.index0?"next":"prev",s=Math.sign(t.detail||t.deltaX)>0?"next":"prev";if(e.prevTime=e.currentTime,!e.state.isAnimating&&i>80){var a=2===t.axis||Math.abs(t.deltaY)&&Math.abs(t.deltaX)<=1,r=1===t.axis||Math.abs(t.deltaX)&&Math.abs(t.deltaY)<=1;if(a)return e.navigate("section",n);if(r)return e.navigate("slide",s)}},o=function(t){return void 0===t&&(t=""),t.split(" ").join("-").toLowerCase()},c=function(t){Object.assign(this,t),this.baseSelector="js-deck3000",this.element=document.querySelector("."+this.baseSelector),this.emitter=e,this.state={current:0,next:1},this.init(),this._onTransitionEnd=this._onTransitionEnd.bind(this)};return c.prototype.init=function(){var t=this,i=this.state.current,n=Array.from(this.element.children).map(function(e,i,n){var r=window.location.pathname.split("/")[1];return t.state.sectionLength=t.state.prev=n.length-1,t.updateURL&&r&&(r!==o(e.dataset.title)&&r!==i.toString()||a({state:t.state,currentKey:"current",currentIndex:i,length:t.state.sectionLength,direction:i})),new s({slideshow:t,slideSelector:t.slideSelector,element:e,index:i})});this.sections=n,e.emit("navigate",this.state),e.emit("navigateSlide",{current:i}),setTimeout(function(){t.element.classList.add("is-init"),t.transitionDuration=1e3*parseFloat(getComputedStyle(t.sections[0].element).transitionDuration),t._attachEventHandlers(),t.onInit&&t.onInit(t._getCallbackState())},0)},c.prototype._attachEventHandlers=function(){var t,e,i,n,s,a=this;this.scrolls=[],this.prevTime=(new Date).getTime(),this.element.addEventListener("mousewheel",function(t){r(t,a)}),this.element.addEventListener("DOMMouseScroll",function(t){r(t,a)}),t=this,e=0,i=0,n=0,s=0,("ontouchstart"in window||navigator.msMaxTouchPoints>0||navigator.maxTouchPoints)&&(t.element.addEventListener("touchstart",function(t){e=t.changedTouches[0].screenX,i=t.changedTouches[0].screenY},!1),t.element.addEventListener("touchend",function(a){n=a.changedTouches[0].screenX,s=a.changedTouches[0].screenY;var r=Math.abs(n-e)>=100,o=Math.abs(s-i)>=100;return n<=e&&r?t.navigate("slide","next"):n>=e&&r?t.navigate("slide","prev"):s>=i&&o?t.navigate("section","prev"):s<=i&&o?t.navigate("section","next"):void 0},!1)),this.keyboardEvents&&window.addEventListener("keyup",function(t){if(!a.noEvents&&!a.state.isAnimating)switch(t.keyCode){case 38:a.navigate("section","prev");break;case 40:a.navigate("section","next");break;case 37:a.navigate("slide","prev");break;case 39:a.navigate("slide","next")}})},c.prototype.disableEvents=function(t){this.noEvents=t},c.prototype.navigate=function(t,i,n,s){var r=this;if(!this.noEvents&&!this.state.isAnimating){var c=this.state,l=c.current,h=c.sectionLength,d=this.sections[l],u="section"===t,v=u?d.element:d.slides[d.state.currentSlide].element,m=u?this.onSectionStart:this.onSlideStart,p=u?this.onSectionEnd:this.onSlideEnd;if(this.state.isAnimating=!n,this.state.direction=i,u)a({state:this.state,currentKey:"current",currentIndex:l,length:h,direction:i}),this.updateURL&&!n&&function(t,e){var i=o((e||t.current).toString());history.replaceState(t,e,i)}(this.state,this.sections[this.state.current].element.dataset.title),e.emit("navigate",this.state);else{var g=d,f=g.state,S=f.currentSlide,x=f.slideLength;n&&(g=this._getNextSection(s)),a({state:g.state,currentKey:"currentSlide",currentIndex:S,length:x,direction:i}),e.emit("navigateSlide",{current:l,direction:i,reset:n})}n||(m&&m(this._getCallbackState()),clearTimeout(this.timeout),this.timeout=setTimeout(function(){r._onTransitionEnd({element:v,onEnd:p,isSection:u,direction:i})},n?0:this.transitionDuration))}},c.prototype._getCallbackState=function(){var t=this.sections[this.state.current];return{section:this.state,slide:t.state,currentSectionElem:t.element,currentSlideElem:t.getCurrentSlide()}},c.prototype._getNextSection=function(t){var e=this.state;return"next"===t?this.sections[e.prev]:this.sections[e.next]},c.prototype._onTransitionEnd=function(t){var e=t.onEnd,i=t.isSection,n=t.direction;this.state.isAnimating=!1,i&&this.resetSlides&&this.navigate("slide",0,!0,n),e&&t.onEnd(this._getCallbackState())},c}); 2 | //# sourceMappingURL=deck3000.umd.js.map 3 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 |

Deck3000

A1/3
Infinite fullpage slides
Scroll, arrows keys, touch
URLs enabled

Deck3000

A2/3

Deck3000

A3/3

Deck3000

B1/4

Deck3000

B2/4

Deck3000

B3/4

Deck3000

B3/4

Deck3000

C1/1

Deck3000

D1/3

Deck3000

D2/3

Deck3000

D3/3

-------------------------------------------------------------------------------- /docs/src.461479b2.js: -------------------------------------------------------------------------------- 1 | parcelRequire=function(e,r,n,t){function i(n,t){function o(e){return i(o.resolve(e))}function c(r){return e[n][1][r]||r}if(!r[n]){if(!e[n]){var l="function"==typeof parcelRequire&&parcelRequire;if(!t&&l)return l(n,!0);if(u)return u(n,!0);if(f&&"string"==typeof n)return f(n);var p=new Error("Cannot find module '"+n+"'");throw p.code="MODULE_NOT_FOUND",p}o.resolve=c;var a=r[n]=new i.Module(n);e[n][0].call(a.exports,o,a,a.exports,this)}return r[n].exports}function o(e){this.id=e,this.bundle=i,this.exports={}}var u="function"==typeof parcelRequire&&parcelRequire,f="function"==typeof require&&require;i.isParcelRequire=!0,i.Module=o,i.modules=e,i.cache=r,i.parent=u;for(var c=0;c>>0,1)},emit:function(e,i){(t[e]||[]).slice().map(function(t){t(i)}),(t["*"]||[]).slice().map(function(t){t(e,i)})}}),i=function(t,e){var i;t.index===e.current?i="current":t.index===e.next?i="next":t.index===e.prev?i="prev":t.index>e.current?i="next":t.index0?"next":"prev",s=Math.sign(t.detail||t.deltaX)>0?"next":"prev";if(e.prevTime=e.currentTime,!e.state.isAnimating&&i>80){var a=2===t.axis||Math.abs(t.deltaY)&&Math.abs(t.deltaX)<=1,r=1===t.axis||Math.abs(t.deltaX)&&Math.abs(t.deltaY)<=1;if(a)return e.navigate("section",n);if(r)return e.navigate("slide",s)}},o=function(t){return void 0===t&&(t=""),t.split(" ").join("-").toLowerCase()},c=function(t){Object.assign(this,t),this.baseSelector="js-deck3000",this.element=document.querySelector("."+this.baseSelector),this.emitter=e,this.state={current:0,next:1},this.init(),this._onTransitionEnd=this._onTransitionEnd.bind(this)};c.prototype.init=function(){var t=this,i=this.state.current,n=Array.from(this.element.children).map(function(e,i,n){var r=window.location.pathname.split("/")[1];return t.state.sectionLength=t.state.prev=n.length-1,t.updateURL&&r&&(r!==o(e.dataset.title)&&r!==i.toString()||a({state:t.state,currentKey:"current",currentIndex:i,length:t.state.sectionLength,direction:i})),new s({slideshow:t,slideSelector:t.slideSelector,element:e,index:i})});this.sections=n,e.emit("navigate",this.state),e.emit("navigateSlide",{current:i}),setTimeout(function(){t.element.classList.add("is-init"),t.transitionDuration=1e3*parseFloat(getComputedStyle(t.sections[0].element).transitionDuration),t._attachEventHandlers(),t.onInit&&t.onInit(t._getCallbackState())},0)},c.prototype._attachEventHandlers=function(){var t,e,i,n,s,a=this;this.scrolls=[],this.prevTime=(new Date).getTime(),this.element.addEventListener("mousewheel",function(t){r(t,a)}),this.element.addEventListener("DOMMouseScroll",function(t){r(t,a)}),t=this,e=0,i=0,n=0,s=0,("ontouchstart"in window||navigator.msMaxTouchPoints>0||navigator.maxTouchPoints)&&(t.element.addEventListener("touchstart",function(t){e=t.changedTouches[0].screenX,i=t.changedTouches[0].screenY},!1),t.element.addEventListener("touchend",function(a){n=a.changedTouches[0].screenX,s=a.changedTouches[0].screenY;var r=Math.abs(n-e)>=100,o=Math.abs(s-i)>=100;return n<=e&&r?t.navigate("slide","next"):n>=e&&r?t.navigate("slide","prev"):s>=i&&o?t.navigate("section","prev"):s<=i&&o?t.navigate("section","next"):void 0},!1)),this.keyboardEvents&&window.addEventListener("keyup",function(t){if(!a.noEvents&&!a.state.isAnimating)switch(t.keyCode){case 38:a.navigate("section","prev");break;case 40:a.navigate("section","next");break;case 37:a.navigate("slide","prev");break;case 39:a.navigate("slide","next")}})},c.prototype.disableEvents=function(t){this.noEvents=t},c.prototype.navigate=function(t,i,n,s){var r=this;if(!this.noEvents&&!this.state.isAnimating){var c=this.state,l=c.current,h=c.sectionLength,d=this.sections[l],u="section"===t,v=u?d.element:d.slides[d.state.currentSlide].element,m=u?this.onSectionStart:this.onSlideStart,p=u?this.onSectionEnd:this.onSlideEnd;if(this.state.isAnimating=!n,this.state.direction=i,u)a({state:this.state,currentKey:"current",currentIndex:l,length:h,direction:i}),this.updateURL&&!n&&function(t,e){var i=o((e||t.current).toString());history.replaceState(t,e,i)}(this.state,this.sections[this.state.current].element.dataset.title),e.emit("navigate",this.state);else{var g=d,f=g.state,S=f.currentSlide,x=f.slideLength;n&&(g=this._getNextSection(s)),a({state:g.state,currentKey:"currentSlide",currentIndex:S,length:x,direction:i}),e.emit("navigateSlide",{current:l,direction:i,reset:n})}n||(m&&m(this._getCallbackState()),clearTimeout(this.timeout),this.timeout=setTimeout(function(){r._onTransitionEnd({element:v,onEnd:p,isSection:u,direction:i})},n?0:this.transitionDuration))}},c.prototype._getCallbackState=function(){var t=this.sections[this.state.current];return{section:this.state,slide:t.state,currentSectionElem:t.element,currentSlideElem:t.getCurrentSlide()}},c.prototype._getNextSection=function(t){var e=this.state;return"next"===t?this.sections[e.prev]:this.sections[e.next]},c.prototype._onTransitionEnd=function(t){var e=t.onEnd,i=t.isSection,n=t.direction;this.state.isAnimating=!1,i&&this.resetSlides&&this.navigate("slide",0,!0,n),e&&t.onEnd(this._getCallbackState())},module.exports=c; 3 | },{}],6:[function(require,module,exports) { 4 | "use strict";var e=require("../../dist/deck3000"),t=i(e);function i(e){return e&&e.__esModule?e:{default:e}}var s=document.querySelector(".indicator"),r=Array.from(s.querySelectorAll("g"));console.log(r);var c=new t.default({resetSlides:!0,keyboardEvents:!0,updateURL:!0,onInit:function(e){console.log(e),r[e.section.current].classList.add("is-active"),s.dataset.slide=0},onSectionStart:function(e){document.querySelector(".is-active").classList.remove("is-active"),r[e.section.current].classList.add("is-active"),s.dataset.slide=0},onSlideStart:function(e){s.dataset.slide=e.slide.currentSlide}}); 5 | },{"../../dist/deck3000":10}]},{},[6], null) -------------------------------------------------------------------------------- /docs/style.499f78c8.css: -------------------------------------------------------------------------------- 1 | .js-deck3000{width:100vw;height:100%;position:fixed;top:0;left:0;overflow:hidden}.js-deck3000__section,.js-deck3000__section-slide{width:100%;height:100%;position:absolute;overflow:hidden}.is-init .js-deck3000__section,.is-init .js-deck3000__section-slide{transition-property:transform;transition-duration:.5s}.js-deck3000__section-slide{top:0}.js-deck3000__section-slide.is-current,.js-deck3000__section.is-current{top:0;left:0;transform:translateZ(0)}.js-deck3000__section.is-next{transform:translate3d(0,100%,0)}.js-deck3000__section.is-prev{transform:translate3d(0,-100%,0)}.js-deck3000__section-slide.is-instant,.js-deck3000__section.is-instant{transition:none}.js-deck3000__section-slide.is-next{transform:translate3d(100%,0,0)}.js-deck3000__section-slide.is-prev{transform:translate3d(-100%,0,0)}body,html{width:100%;height:100%;overflow:hidden;margin:0;padding:0}body{font-family:Arial,sans-serif;font-weight:700;-webkit-font-smoothing:antialiased}section{background:#000;color:#fff;text-transform:uppercase}section h1,section p{margin:0;font-weight:400;font-size:24px;line-height:.9;font-weight:700}.overlay{width:100%;height:100%;position:fixed;top:0;left:0;z-index:9999;display:flex;pointer-events:none}.indicator{object-fit:contain;margin:auto}@media (min-width:720px){.indicator{width:100%;height:70%}}@media (max-width:720px){.indicator{width:80%;height:100%}}.indicator__section{white-space:nowrap}.indicator__section+.indicator__section{margin-top:8px}rect{stroke:#fff;stroke-width:1;fill:none}[data-slide="0"] .is-active rect:first-child,[data-slide="1"] .is-active rect:nth-child(2),[data-slide="2"] .is-active rect:nth-child(3),[data-slide="3"] .is-active rect:nth-child(4),[data-slide="4"] .is-active rect:nth-child(5){fill:#fff} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deck3000", 3 | "version": "1.0.12", 4 | "description": "Slider component for the new millenium", 5 | "license": "MIT", 6 | "authors": [ 7 | "Ezekiel Aquino " 8 | ], 9 | "repository": "ezekielaquino/Deck3000", 10 | "keywords": [ 11 | "deck", 12 | "fullpage", 13 | "full page", 14 | "onepage", 15 | "one page", 16 | "single page", 17 | "slides", 18 | "slider", 19 | "slide" 20 | ], 21 | "scripts": { 22 | "build:dist": "microbundle --target=browser --strict --name=Deck3000", 23 | "build:docs": "microbundle --target=browser --strict --output './docs' --name=Deck3000", 24 | "build": "yarn build:dist & yarn build:docs", 25 | "dev": "microbundle watch" 26 | }, 27 | "source": "src/index.js", 28 | "main": "dist/deck3000.js", 29 | "module": "dist/deck3000.es.js", 30 | "umd:main": "dist/deck3000.umd.js", 31 | "dependencies": { 32 | "mitt": "^1.1.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Emitter.js: -------------------------------------------------------------------------------- 1 | import mitt from 'mitt'; 2 | 3 | const Emitter = mitt(); 4 | 5 | export default Emitter; -------------------------------------------------------------------------------- /src/MouseWheel.js: -------------------------------------------------------------------------------- 1 | const MouseWheel = (e, instance) => { 2 | instance.currentTime = new Date().getTime(); 3 | 4 | const timeDiff = instance.currentTime - (instance.prevTime || 0); 5 | const directionY = Math.sign(e.detail || e.deltaY) > 0 ? 'next' : 'prev'; 6 | const directionX = Math.sign(e.detail || e.deltaX) > 0 ? 'next' : 'prev'; 7 | 8 | instance.prevTime = instance.currentTime; 9 | 10 | if (!instance.state.isAnimating && timeDiff > 80) { 11 | const isY = e.axis === 2 || (Math.abs(e.deltaY) && Math.abs(e.deltaX) <= 1); 12 | const isX = e.axis === 1 || (Math.abs(e.deltaX) && Math.abs(e.deltaY) <= 1); 13 | 14 | if (isY) return instance.navigate('section', directionY); 15 | if (isX) return instance.navigate('slide', directionX); 16 | } 17 | }; 18 | 19 | export default MouseWheel; -------------------------------------------------------------------------------- /src/Section.js: -------------------------------------------------------------------------------- 1 | import Emitter from './Emitter'; 2 | import Slide from './Slide'; 3 | import SetPosition from './SetPosition'; 4 | 5 | class Section { 6 | constructor(options = {}) { 7 | Object.assign(this, options); 8 | this.className = `${this.slideshow.baseSelector}__section`; 9 | 10 | this.state = { 11 | currentSlide: 0, 12 | }; 13 | 14 | this.init(); 15 | } 16 | 17 | init() { 18 | this.initialClasses = Array.from(this.element.classList); 19 | this.element.classList.add(this.className); 20 | 21 | this._initSlides(); 22 | 23 | this.state.next = this.slides.length && 1; 24 | this.state.prev = this.slides.length && this.slides.length - 1; 25 | 26 | Emitter.on('navigate', e => this._onNavigate(e)); 27 | } 28 | 29 | getCurrentSlide() { 30 | return this.slides[this.state.currentSlide].element; 31 | } 32 | 33 | _initSlides() { 34 | const children = Array.from(this.slideSelector ? this.element.querySelectorAll(this.slideSelector) : this.element.children); 35 | 36 | if (children.length === 2) { 37 | const clone = children[0].cloneNode(true); 38 | this.element.appendChild(clone); 39 | children.push(clone); 40 | } 41 | 42 | this.state.slideLength = children.length - 1; 43 | 44 | const slides = Array.from(children).map((element, index) => { 45 | return new Slide({ 46 | parentSection: this, 47 | element, 48 | index, 49 | }); 50 | }); 51 | 52 | this.slides = slides; 53 | } 54 | 55 | _onNavigate(e) { 56 | SetPosition(this, e); 57 | } 58 | } 59 | 60 | export default Section; -------------------------------------------------------------------------------- /src/SetBrowserHistory.js: -------------------------------------------------------------------------------- 1 | import ToSlug from './ToSlug'; 2 | 3 | const SetBrowserHistory = (state, section) => { 4 | const title = section || state.current; 5 | const slug = ToSlug(title.toString()); 6 | 7 | history.replaceState(state, section, slug); 8 | } 9 | 10 | export default SetBrowserHistory; -------------------------------------------------------------------------------- /src/SetCurrentState.js: -------------------------------------------------------------------------------- 1 | const SetCurrentState = (args) => { 2 | const { 3 | state, 4 | currentKey, 5 | direction, 6 | currentIndex, 7 | length 8 | } = args; 9 | 10 | if (Number.isInteger(direction)) { 11 | state[currentKey] = direction; 12 | } else { 13 | state.direction = direction; 14 | 15 | switch (direction) { 16 | case 'next': 17 | if (currentIndex !== length) state[currentKey] += 1; 18 | else state[currentKey] = 0; 19 | break; 20 | case 'prev': 21 | if (currentIndex !== 0) state[currentKey] -= 1; 22 | else state[currentKey] = length; 23 | break; 24 | } 25 | } 26 | 27 | state.next = state[currentKey] === length ? 0 : state[currentKey] + 1; 28 | state.prev = state[currentKey] === 0 ? length : state[currentKey] - 1; 29 | } 30 | 31 | export default SetCurrentState; -------------------------------------------------------------------------------- /src/SetPosition.js: -------------------------------------------------------------------------------- 1 | import ToggleClass from './ToggleClass'; 2 | 3 | const SetPosition = (instance, state) => { 4 | let position; 5 | 6 | if (instance.index === state.current) position = 'current'; 7 | else if (instance.index === state.next) position = 'next'; 8 | else if (instance.index === state.prev) position = 'prev'; 9 | else if (instance.index > state.current) position = 'next'; 10 | else if (instance.index < state.current) position = 'prev'; 11 | 12 | ToggleClass({ 13 | target: instance.element, 14 | targetClass: instance.className, 15 | initialClasses: instance.initialClasses, 16 | classNames: [`is-${position}`], 17 | direction: state.direction, 18 | reset: state.reset, 19 | }); 20 | }; 21 | 22 | export default SetPosition; -------------------------------------------------------------------------------- /src/Slide.js: -------------------------------------------------------------------------------- 1 | import Emitter from './Emitter'; 2 | import SetPosition from './SetPosition'; 3 | 4 | class Slide { 5 | constructor(options = {}) { 6 | Object.assign(this, options); 7 | this.sectionIndex = options.parentSection.index; 8 | this.className = `${this.parentSection.className}-slide`; 9 | this.init(); 10 | } 11 | 12 | init() { 13 | this.initialClasses = Array.from(this.element.classList); 14 | this.element.classList.add(this.className); 15 | 16 | if (this.parentSection.state.slideLength === 0) { 17 | return this.element.classList.add('is-current'); 18 | } 19 | 20 | Emitter.on('navigateSlide', e => this._onNavigate(e)); 21 | } 22 | 23 | _onNavigate(e) { 24 | const { current, direction, reset } = e; 25 | const { currentSlide, next, prev } = this.parentSection.state; 26 | 27 | if (this.sectionIndex === current || !direction) { 28 | SetPosition(this, { 29 | current: currentSlide, 30 | direction, 31 | next, 32 | prev, 33 | reset, 34 | }); 35 | } 36 | } 37 | } 38 | 39 | export default Slide; -------------------------------------------------------------------------------- /src/ToSlug.js: -------------------------------------------------------------------------------- 1 | const ToSlug = (string = '') => { 2 | return string.split(' ').join('-').toLowerCase(); 3 | }; 4 | 5 | export default ToSlug; -------------------------------------------------------------------------------- /src/ToggleClass.js: -------------------------------------------------------------------------------- 1 | const ToggleClass = (args) => { 2 | const { 3 | target, 4 | targetClass, 5 | initialClasses, 6 | classNames, 7 | direction, 8 | reset, 9 | } = args; 10 | const isInstant = direction === 'next' ? 'is-next' :'is-prev'; 11 | 12 | target.classList.add(...classNames); 13 | 14 | const classes = Array.from(target.classList).filter(c => { 15 | if (c === targetClass || classNames.includes(c) || initialClasses.includes(c)) return c; 16 | }); 17 | 18 | if (classNames.includes(isInstant) || reset) classes.push('is-instant'); 19 | 20 | return target.classList = classes.join(' '); 21 | }; 22 | 23 | export default ToggleClass; -------------------------------------------------------------------------------- /src/TouchEvents.js: -------------------------------------------------------------------------------- 1 | const TouchEvents = instance => { 2 | const isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 3 | let touchStartX = 0; 4 | let touchStartY = 0; 5 | let touchEndX = 0; 6 | let touchEndY = 0; 7 | 8 | if (isTouch) { 9 | instance.element.addEventListener('touchstart', e => { 10 | touchStartX = e.changedTouches[0].screenX; 11 | touchStartY = e.changedTouches[0].screenY; 12 | }, false); 13 | 14 | instance.element.addEventListener('touchend', e => { 15 | touchEndX = e.changedTouches[0].screenX; 16 | touchEndY = e.changedTouches[0].screenY; 17 | 18 | const diffX = Math.abs(touchEndX - touchStartX) >= 100; 19 | const diffY = Math.abs(touchEndY - touchStartY) >= 100; 20 | 21 | if (touchEndX <= touchStartX && diffX) { 22 | // left 23 | return instance.navigate('slide', 'next'); 24 | } 25 | if (touchEndX >= touchStartX && diffX) { 26 | // right 27 | return instance.navigate('slide', 'prev'); 28 | } 29 | if (touchEndY >= touchStartY && diffY) { 30 | // down 31 | return instance.navigate('section', 'prev'); 32 | } 33 | if (touchEndY <= touchStartY && diffY) { 34 | // up 35 | return instance.navigate('section', 'next'); 36 | } 37 | }, false); 38 | } 39 | } 40 | 41 | export default TouchEvents; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Emitter from './Emitter'; 2 | import Section from './Section'; 3 | import SetCurrentState from './SetCurrentState'; 4 | import MouseWheel from './MouseWheel'; 5 | import TouchEvents from './TouchEvents'; 6 | import ToSlug from './ToSlug'; 7 | import SetBrowserHistory from './SetBrowserHistory'; 8 | 9 | class Deck3000 { 10 | constructor(options) { 11 | Object.assign(this, options); 12 | this.baseSelector = 'js-deck3000'; 13 | this.element = document.querySelector(`.${this.baseSelector}`); 14 | this.emitter = Emitter; 15 | this.state = { 16 | current: 0, 17 | next: 1, 18 | }; 19 | 20 | this.init(); 21 | this._onTransitionEnd = this._onTransitionEnd.bind(this); 22 | } 23 | 24 | init() { 25 | const { current } = this.state; 26 | const sections = Array.from(this.element.children).map((element, index, array) => { 27 | const path = window.location.pathname.split('/')[1]; 28 | 29 | this.state.sectionLength = this.state.prev = array.length - 1; 30 | 31 | if (this.updateURL && path) { 32 | if (path === ToSlug(element.dataset.title) || path === index.toString()) { 33 | SetCurrentState({ 34 | state: this.state, 35 | currentKey: 'current', 36 | currentIndex: index, 37 | length: this.state.sectionLength, 38 | direction: index, 39 | }); 40 | } 41 | } 42 | 43 | return new Section({ 44 | slideshow: this, 45 | slideSelector: this.slideSelector, 46 | element, 47 | index, 48 | }); 49 | }); 50 | 51 | this.sections = sections; 52 | 53 | Emitter.emit('navigate', this.state); 54 | Emitter.emit('navigateSlide', { current }); 55 | 56 | setTimeout(() => { 57 | this.element.classList.add('is-init'); 58 | this.transitionDuration = parseFloat(getComputedStyle(this.sections[0].element)['transitionDuration']) * 1000; 59 | this._attachEventHandlers(); 60 | 61 | if (this.onInit) this.onInit(this._getCallbackState()); 62 | }, 0); 63 | } 64 | 65 | _attachEventHandlers() { 66 | this.scrolls = []; 67 | this.prevTime = new Date().getTime(); 68 | 69 | this.element.addEventListener('mousewheel', e => { MouseWheel(e, this) }); 70 | this.element.addEventListener('DOMMouseScroll', e => { MouseWheel(e, this) }); 71 | 72 | TouchEvents(this); 73 | 74 | if (this.keyboardEvents) { 75 | window.addEventListener('keyup', e => { 76 | if (this.noEvents || this.state.isAnimating) return; 77 | 78 | switch (e.keyCode) { 79 | case 38: // up 80 | this.navigate('section', 'prev'); 81 | break; 82 | case 40: // down 83 | this.navigate('section', 'next'); 84 | break; 85 | case 37: // left 86 | this.navigate('slide', 'prev'); 87 | break; 88 | case 39: // right 89 | this.navigate('slide', 'next'); 90 | break; 91 | } 92 | }); 93 | } 94 | } 95 | 96 | disableEvents(bool) { 97 | this.noEvents = bool; 98 | } 99 | 100 | navigate(type, direction, reset, resetDirection) { 101 | if (this.noEvents || this.state.isAnimating) return; 102 | 103 | const { current, prev, next, sectionLength } = this.state; 104 | const currentSection = this.sections[current]; 105 | const currentSlide = currentSection.slides[currentSection.state.currentSlide]; 106 | const isSection = type === 'section'; 107 | const element = isSection ? currentSection.element : currentSlide.element; 108 | const onStart = isSection ? this.onSectionStart : this.onSlideStart; 109 | const onEnd = isSection ? this.onSectionEnd : this.onSlideEnd; 110 | 111 | this.state.isAnimating = !reset; 112 | this.state.direction = direction; 113 | 114 | if (isSection) { 115 | SetCurrentState({ 116 | state: this.state, 117 | currentKey: 'current', 118 | currentIndex: current, 119 | length: sectionLength, 120 | direction, 121 | }); 122 | 123 | if (this.updateURL && !reset) { 124 | SetBrowserHistory(this.state, this.sections[this.state.current].element.dataset.title); 125 | } 126 | 127 | Emitter.emit('navigate', this.state); 128 | } else { 129 | let section = currentSection; 130 | const { currentSlide, slideLength } = section.state; 131 | 132 | if (reset) section = this._getNextSection(resetDirection); 133 | 134 | SetCurrentState({ 135 | state: section.state, 136 | currentKey: 'currentSlide', 137 | currentIndex: currentSlide, 138 | length: slideLength, 139 | direction, 140 | }); 141 | 142 | Emitter.emit('navigateSlide', { 143 | current, 144 | direction, 145 | reset, 146 | }); 147 | } 148 | 149 | if (!reset) { 150 | if (onStart) onStart(this._getCallbackState()); 151 | 152 | clearTimeout(this.timeout); 153 | 154 | this.timeout = setTimeout(() => { 155 | this._onTransitionEnd({ 156 | element, 157 | onEnd, 158 | isSection, 159 | direction, 160 | }); 161 | }, reset ? 0 : this.transitionDuration); 162 | } 163 | } 164 | 165 | _getCallbackState() { 166 | const currentSection = this.sections[this.state.current]; 167 | 168 | return { 169 | section: this.state, 170 | slide: currentSection.state, 171 | currentSectionElem: currentSection.element, 172 | currentSlideElem: currentSection.getCurrentSlide(), 173 | } 174 | } 175 | 176 | _getNextSection(direction) { 177 | const { next, prev } = this.state; 178 | return direction === 'next' ? this.sections[prev] : this.sections[next]; 179 | } 180 | 181 | _onTransitionEnd(args) { 182 | const { element, onEnd, isSection, direction } = args; 183 | 184 | this.state.isAnimating = false; 185 | 186 | if (isSection && this.resetSlides) this.navigate('slide', 0, true, direction); 187 | if (onEnd) args.onEnd(this._getCallbackState()); 188 | } 189 | } 190 | 191 | export default Deck3000; --------------------------------------------------------------------------------