UNPKG

panelsnap

Version:

A JavaScript plugin that provides snapping functionality to a set of panels within your interface.

9 lines (8 loc) 9.49 kB
/** * PanelSnap.js v1.3.0 * Copyright (c) 2013-present, Guido Bouman * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ "use strict";function _interopDefault(t){return t&&"object"==typeof t&&"default"in t?t.default:t}var Tweezer=_interopDefault(require("tweezer.js"));function _classCallCheck(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _defineProperties(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function _createClass(t,e,n){return e&&_defineProperties(t.prototype,e),n&&_defineProperties(t,n),t}function _defineProperty(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function _objectSpread(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){_defineProperty(t,e,n[e])})}return t}function _toConsumableArray(t){return _arrayWithoutHoles(t)||_iterableToArray(t)||_nonIterableSpread()}function _arrayWithoutHoles(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}function _iterableToArray(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function getScrollingElement(t){return t!==document.body?t:"scrollingElement"in document?document.scrollingElement:navigator.userAgent.indexOf("WebKit")>-1?document.body:document.documentElement}function getScrollEventContainer(t){return t===document.body?window:getScrollingElement(t)}function getContainerRect(t){if(t===document.body){var e=document.documentElement;return{top:0,left:0,bottom:e.clientHeight,right:e.clientWidth,height:e.clientHeight,width:e.clientWidth}}return t.getBoundingClientRect()}function getTargetScrollOffset(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=arguments.length>3&&void 0!==arguments[3]&&arguments[3],o=getContainerRect(t),r=e.getBoundingClientRect(),s=r.top-o.top,a=r.left-o.left,l=n?r.height-o.height:0,c=i?r.width-o.width:0,h=getScrollingElement(t);return{top:s+l+h.scrollTop,left:a+c+h.scrollLeft}}function getElementsInContainerViewport(t,e){var n=getContainerRect(t);return e.filter(function(t){var e=t.getBoundingClientRect();return e.top<n.bottom&&e.right>n.left&&e.bottom>n.top&&e.left<n.right})}function elementFillsContainer(t,e){var n=getContainerRect(t),i=e.getBoundingClientRect();return i.top<=n.top&&i.bottom>=n.bottom&&i.left<=n.left&&i.right>=n.right}var passiveIsSupported=function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}(),INSTANCE_COUNTER=0,TWEEN_MAX_VALUE=1e4,defaultOptions={container:document.body,panelSelector:"> section",directionThreshold:50,delay:0,duration:300,easing:function(t){return t}},PanelSnap=function(){function t(e){if(_classCallCheck(this,t),this.options=_objectSpread({},defaultOptions,e),this.options.container.dataset.panelsnapId)throw new Error("PanelSnap is already initialised on this container, aborting.");this.container=this.options.container,this.scrollContainer=getScrollingElement(this.container),this.scrollEventContainer=getScrollEventContainer(this.container),INSTANCE_COUNTER+=1,this.instanceIndex=INSTANCE_COUNTER,this.container.dataset.panelsnapId=this.instanceIndex;var n='[data-panelsnap-id="'.concat(this.instanceIndex,'"] ').concat(this.options.panelSelector);this.panelList=Array.from(document.querySelectorAll(n)),this.events=[],this.isEnabled=!0,this.isInteracting=!1,this.scrollTimeout=null,this.resetAnimation(),this.onInteractStart=this.onInteractStart.bind(this),this.onInteractStop=this.onInteractStop.bind(this),this.onInteractStart=this.onInteractStart.bind(this),this.onInteractStop=this.onInteractStop.bind(this),this.onInteractStart=this.onInteractStart.bind(this),this.onInteractStop=this.onInteractStop.bind(this),this.onScroll=this.onScroll.bind(this),this.onInteract=this.onInteract.bind(this),this.scrollEventContainer.addEventListener("keydown",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("keyup",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("mousedown",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("mouseup",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("touchstart",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("touchend",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("scroll",this.onScroll,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.addEventListener("wheel",this.onInteract,passiveIsSupported&&{passive:!0}),this.findSnapTarget()}return _createClass(t,[{key:"destroy",value:function(){this.stopAnimation(),this.disable(),this.scrollEventContainer.removeEventListener("keydown",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("keyup",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("mousedown",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("mouseup",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("touchstart",this.onInteractStart,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("touchend",this.onInteractStop,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("scroll",this.onScroll,passiveIsSupported&&{passive:!0}),this.scrollEventContainer.removeEventListener("wheel",this.onInteract,passiveIsSupported&&{passive:!0}),delete this.options.container.dataset.panelsnapId}},{key:"enable",value:function(){this.isEnabled=!0}},{key:"disable",value:function(){this.isEnabled=!1}},{key:"on",value:function(t,e){var n=this.events[t]||[];this.events[t]=_toConsumableArray(n).concat([e]),"activatePanel"===t&&e.call(this,this.activePanel)}},{key:"off",value:function(t,e){var n=this.events[t]||[];this.events[t]=n.filter(function(t){return t!==e})}},{key:"emit",value:function(t,e){var n=this;(this.events[t]||[]).forEach(function(t){return t.call(n,e)})}},{key:"onInteractStart",value:function(){this.stopAnimation(),this.isInteracting=!0}},{key:"onInteractStop",value:function(){this.isInteracting=!1,this.findSnapTarget()}},{key:"onInteract",value:function(){this.stopAnimation(),this.onScroll()}},{key:"onScroll",value:function(){clearTimeout(this.scrollTimeout),this.isInteracting||this.animation||(this.scrollTimeout=setTimeout(this.findSnapTarget.bind(this),50+this.options.delay))}},{key:"findSnapTarget",value:function(){var t=this.scrollContainer.scrollTop-this.currentScrollOffset.top,e=this.scrollContainer.scrollLeft-this.currentScrollOffset.left;this.currentScrollOffset={top:this.scrollContainer.scrollTop,left:this.scrollContainer.scrollLeft};var n=getElementsInContainerViewport(this.container,this.panelList);if(0===n.length)throw new Error("PanelSnap could not find a snappable panel, aborting.");if(n.length>1){if(Math.abs(t)<this.options.directionThreshold&&Math.abs(e)<this.options.directionThreshold&&this.activePanel)return void this.snapToPanel(this.activePanel,t>0,e>0);var i=t>0||e>0?1:n.length-2;this.snapToPanel(n[i],t<0,e<0)}else{var o=n[0];elementFillsContainer(this.container,o)?this.activatePanel(o):(console.error("PanelSnap does not support space between panels, snapping back."),this.snapToPanel(o,t>0,e>0))}}},{key:"snapToPanel",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this.activatePanel(t),this.isEnabled&&(this.animation&&this.animation.stop(),this.targetScrollOffset=getTargetScrollOffset(this.container,t,n,i),this.animation=new Tweezer({start:0,end:TWEEN_MAX_VALUE,duration:this.options.duration}),this.animation.on("tick",this.animationTick.bind(this)),this.animation.on("done",function(){e.emit("snapStop",t),e.resetAnimation()}),this.emit("snapStart",t),this.animation.begin())}},{key:"animationTick",value:function(t){var e=this.targetScrollOffset.top-this.currentScrollOffset.top,n=this.currentScrollOffset.top+e*t/TWEEN_MAX_VALUE;this.scrollContainer.scrollTop=n;var i=this.targetScrollOffset.left-this.currentScrollOffset.left,o=this.currentScrollOffset.left+i*t/TWEEN_MAX_VALUE;this.scrollContainer.scrollLeft=o}},{key:"stopAnimation",value:function(){this.animation&&(this.animation.stop(),this.resetAnimation())}},{key:"resetAnimation",value:function(){this.currentScrollOffset={top:this.scrollContainer.scrollTop,left:this.scrollContainer.scrollLeft},this.targetScrollOffset={top:0,left:0},this.animation=null}},{key:"activatePanel",value:function(t){this.activePanel!==t&&(this.emit("activatePanel",t),this.activePanel=t)}}]),t}();module.exports=PanelSnap;