UNPKG

two-dimension-scroll

Version:

A smooth scroll library that detects both horizontal and vertical scroll and converts them to vertical smooth scrolling

2 lines (1 loc) 18.8 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("react");function o(){function t(t,o,i){return Math.min(Math.max(t,o),i)}function o(){return"undefined"==typeof document?0:Math.max(document.body.scrollHeight-window.innerHeight,document.documentElement.scrollHeight-window.innerHeight,0)}var i="undefined"==typeof window?function(t){return setTimeout(t,16)}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||function(t){return setTimeout(t,16)},e="undefined"==typeof window?clearTimeout:window.cancelAnimationFrame||window.webkitCancelAnimationFrame||clearTimeout;function n(t){t=t||{},this.currentEnvironment=function(){if("undefined"==typeof window)return"desktop";var t=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),o="ontouchstart"in window||navigator.maxTouchPoints>0,i=window.innerWidth<=768,e=/iPad|Android(?!.*Mobile)|Tablet/i.test(navigator.userAgent)&&window.innerWidth>=768;return t&&!e||i&&o?"mobile":e?"tablet":"desktop"}(),this.isMobileDevice="mobile"===this.currentEnvironment,this.isTabletDevice="tablet"===this.currentEnvironment,this.isDesktopDevice="desktop"===this.currentEnvironment;this.options=this.mergeOptions(t,{disabled:!1,debug:!1,ui:{hideScrollbar:!0,showScrollProgress:!1,customScrollbarStyle:!1},desktop:{duration:1e3,horizontalSensitivity:1.2,verticalSensitivity:1.5,lerp:.1,wheelMultiplier:1.1,precisionMode:!0,keyboardScrollAmount:.8,prioritizeVertical:!1,lockTouchDirection:!0,touchDirectionThreshold:15,allowDirectionChange:!0,directionChangeThreshold:25,directionChangeSmoothness:.3,useAngleBasedDirection:!0,horizontalAngleThreshold:20},mobile:{duration:800,horizontalSensitivity:1.8,verticalSensitivity:2.2,lerp:.15,touchMultiplier:2.5,bounceEffect:!0,flingMultiplier:1.2,touchStopThreshold:4,prioritizeVertical:!1,lockTouchDirection:!0,touchDirectionThreshold:20,allowDirectionChange:!0,directionChangeThreshold:30,directionChangeSmoothness:.4,useAngleBasedDirection:!0,horizontalAngleThreshold:5},tablet:{duration:900,horizontalSensitivity:1.5,verticalSensitivity:1.8,lerp:.12,wheelMultiplier:1.05,touchMultiplier:2.2,hybridMode:!0,prioritizeVertical:!1,lockTouchDirection:!0,touchDirectionThreshold:18,allowDirectionChange:!0,directionChangeThreshold:28,directionChangeSmoothness:.35,useAngleBasedDirection:!0,horizontalAngleThreshold:18}}),this.targetScroll=0,this.animatedScroll=0,this.isScrolling=!1,this.isAnimating=!1,this.rafId=null,this.scrollCallbacks=[],this.passive=!1,this.touchStartY=0,this.touchStartX=0,this.touchStartTime=0,this.lastTouchX=0,this.lastTouchY=0,this.lastTouchTime=0,this.touchVelocityX=0,this.touchVelocityY=0,this.touchMoveCount=0,this.touchStopTimer=null,this.isModalOpen=!1,this.touchDirection=null,this.touchDirectionLocked=!1,this.touchStartDeltaX=0,this.touchStartDeltaY=0,this.oppositeDirectionCount=0,this.lastDeltaX=0,this.lastDeltaY=0,this.smoothedDeltaX=0,this.smoothedDeltaY=0,this.directionChangeStartTime=0,this.verticalScrollDirection=null,this.passive=!!function(){if("undefined"==typeof window)return!1;var t=!1;try{var o=Object.defineProperty({},"passive",{get:function(){return t=!0,!0}});window.addEventListener("testPassive",function(){},o),window.removeEventListener("testPassive",function(){},o)}catch(t){}return t}()&&{passive:!1},this.targetScroll="undefined"==typeof window?0:window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,this.animatedScroll=this.targetScroll,this.environment=this.currentEnvironment,this.init()}return n.prototype.mergeOptions=function(t,o){var i={};for(var e in o)if("desktop"!==e&&"mobile"!==e&&"tablet"!==e)if("ui"===e){i[e]={};var n=o[e]||{},r=t[e]||{};for(var s in n)i[e][s]=n[s];for(var s in r)i[e][s]=r[s]}else i[e]=void 0!==t[e]?t[e]:o[e];var l=o[this.currentEnvironment]||o.desktop,a=t[this.currentEnvironment]||{};for(var h in l)void 0!==t[h]?i[h]=t[h]:void 0!==a[h]?i[h]=a[h]:i[h]=l[h];return i},n.prototype.init=function(){"undefined"!=typeof window&&(this.disableDefaultScroll(),this.setupScrollbarStyles(),this.bindEvents(),this.startAnimationLoop())},n.prototype.setupScrollbarStyles=function(){var t=document.getElementById("twodimension-scrollbar-styles");t&&t.parentNode&&t.parentNode.removeChild(t);var o=document.createElement("style");o.id="twodimension-scrollbar-styles";var i="";!1!==this.options.ui?.hideScrollbar?i="\n /* 스크롤바 숨김 */\n html::-webkit-scrollbar,\n body::-webkit-scrollbar {\n display: none !important;\n }\n html {\n -ms-overflow-style: none !important;\n scrollbar-width: none !important;\n }\n ":this.options.ui?.customScrollbarStyle&&(i="\n /* 커스텀 스크롤바 */\n html {\n -ms-overflow-style: auto !important;\n scrollbar-width: thin !important;\n }\n html::-webkit-scrollbar {\n width: 8px !important;\n }\n html::-webkit-scrollbar-track {\n background: rgba(0,0,0,0.1) !important;\n }\n html::-webkit-scrollbar-thumb {\n background: rgba(0,0,0,0.3) !important;\n border-radius: 4px !important;\n }\n html::-webkit-scrollbar-thumb:hover {\n background: rgba(0,0,0,0.5) !important;\n }\n "),o.textContent="\n html {\n scroll-behavior: auto !important;\n -webkit-overflow-scrolling: touch;\n }\n "+i,document.head.appendChild(o),this.scrollbarStyleElement=o,this.options.debug&&(!1!==this.options.ui?.hideScrollbar||this.options.ui)},n.prototype.disableDefaultScroll=function(){var t=document.createElement("style");t.id="twodimension-base-styles",t.textContent="\n html {\n overflow-x: hidden;\n scroll-behavior: auto;\n }\n body {\n overflow-x: hidden;\n overscroll-behavior: none;\n -webkit-overflow-scrolling: touch;\n }\n ",document.head.appendChild(t),this.styleElement=t;var o=this;this.preventScroll=function(t){if(!(o.options.disabled||t.isPropagationStopped&&"function"==typeof t.isPropagationStopped&&t.isPropagationStopped())){if(o.isModalOpen){for(var i=!1,e=s=r=t.target,n=0;n<10&&e&&e!==document.body;n++){if(e.classList)if((h=e.classList).contains("modal")||h.contains("modal-overlay")||h.contains("modal-content")||h.contains("modal-wrapper")||"dialog"===e.getAttribute("role")||"true"===e.getAttribute("aria-modal")){i=!0;break}e=e.parentElement}return i?void 0:void t.preventDefault()}for(var r,s=r=t.target,l=null;s&&s!==document.body;)if(s.tagName){var a=s.tagName.toLowerCase(),h=s.classList||[],c=s.getAttribute("role")||"",u=s.getAttribute("aria-modal");if("dialog"===a||h.contains("modal")||h.contains("modal-overlay")||h.contains("modal-content")||h.contains("modal-wrapper")||h.contains("modal-container")||h.contains("dialog")||h.contains("popup")||h.contains("overlay")||h.contains("lightbox")||h.contains("backdrop")||"modal-root"===s.id||"portal-root"===s.id||"dialog"===c||"alertdialog"===c||"modal"===c||"true"===u||h.contains("ReactModal__Overlay")||h.contains("ReactModal__Content")){l=s;break}s=s.parentElement}else s=s.parentElement;if(l){if(o.isModalOpen)return;var d=o.findScrollableElement(r,l);if(d){var p=d.scrollTop,m=d.scrollHeight-d.clientHeight;if("wheel"===t.type){var v=t.deltaY||t.detail||t.wheelDelta,b=!1;if((v<0&&p<=0||v>0&&p>=m)&&(b=!0),b)return void t.preventDefault()}else t.type}}else t.preventDefault()}},document.addEventListener("wheel",this.preventScroll,{passive:!1}),document.addEventListener("touchmove",this.preventScroll,{passive:!1})},n.prototype.bindEvents=function(){if("undefined"!=typeof window){var t=this;this.wheelHandler=function(o){t.onWheel(o)},this.options.debug&&(this.globalWheelDetector=function(t){},document.addEventListener("wheel",this.globalWheelDetector,{capture:!0,passive:!0}));var o={passive:!1,capture:!1};document.addEventListener("wheel",this.wheelHandler,o),document.addEventListener("mousewheel",this.wheelHandler,o),document.addEventListener("DOMMouseScroll",this.wheelHandler,o),document.addEventListener("touchstart",function(o){t.onTouchStart(o)},this.passive),document.addEventListener("touchmove",function(o){t.onTouchMove(o)},this.passive),document.addEventListener("touchend",function(o){t.onTouchEnd(o)},this.passive)}},n.prototype.startAnimationLoop=function(){var e=this;!function n(){var r,s,l,a=e.animatedScroll;e.animatedScroll=(r=e.animatedScroll,s=e.targetScroll,(1-(l=e.options.lerp))*r+l*s);var h=o();e.animatedScroll=t(e.animatedScroll,0,h),e.targetScroll=t(e.targetScroll,0,h);var c=Math.abs(e.targetScroll-e.animatedScroll),u=Math.abs(e.animatedScroll-a);if(c<.5&&u<.1)return e.animatedScroll=e.targetScroll,window.scrollTo(0,e.animatedScroll),e.isScrolling=!1,void(e.rafId=null);if(c>.1||u>.05)if(window.scrollTo(0,e.animatedScroll),c>.5){e.isScrolling=!0;for(var d={deltaX:0,deltaY:e.targetScroll-e.animatedScroll,scrollTop:e.animatedScroll,direction:e.targetScroll>e.animatedScroll?1:-1,type:"smooth"},p=0;p<e.scrollCallbacks.length;p++)e.scrollCallbacks[p](d)}else e.isScrolling=!1;e.rafId=i(n)}()},n.prototype.onWheel=function(t){if(this.options.debug,!this.options.disabled){if(this.isModalOpen)return this.options.debug,void this.preventScroll(t);var o=t.deltaX,i=t.deltaY;1===t.deltaMode?(o*=40,i*=40):2===t.deltaMode&&(o*=.8*window.innerHeight,i*=.8*window.innerHeight);var e=this.options.horizontalSensitivity||1,n=this.options.verticalSensitivity||1,r=this.options.wheelMultiplier||1,s=o*e,l=i*n;isNaN(s)&&(s=0),isNaN(l)&&(l=0),this.options.debug;var a=this.calculateCombinedDelta(s,l);isNaN(a)&&(a=0),this.addToScroll(a*r)}},n.prototype.onTouchStart=function(t){if(!this.options.disabled){var o=t.touches[0];this.touchStartX=o.clientX,this.touchStartY=o.clientY,this.touchStartTime=Date.now(),this.lastTouchX=o.clientX,this.lastTouchY=o.clientY,this.lastTouchTime=this.touchStartTime,this.touchVelocityX=0,this.touchVelocityY=0,this.touchMoveCount=0,this.touchDirection=null,this.touchDirectionLocked=!1,this.touchStartDeltaX=0,this.touchStartDeltaY=0,this.oppositeDirectionCount=0,this.lastDeltaX=0,this.lastDeltaY=0,this.smoothedDeltaX=0,this.smoothedDeltaY=0,this.directionChangeStartTime=0,this.verticalScrollDirection=null,this.touchStopTimer&&(clearTimeout(this.touchStopTimer),this.touchStopTimer=null)}},n.prototype.onTouchMove=function(t){if(this.options.debug,!this.options.disabled){var o=t.touches[0],i=Date.now(),e=this.lastTouchX-o.clientX,n=this.lastTouchY-o.clientY;if(Math.sqrt(e*e+n*n)>this.options.touchStopThreshold){this.touchStopTimer&&(clearTimeout(this.touchStopTimer),this.touchStopTimer=null);var r=i-this.lastTouchTime;r>0&&(this.touchVelocityX=e/r,this.touchVelocityY=n/r);var s=e*this.options.horizontalSensitivity*this.options.touchMultiplier,l=n*this.options.verticalSensitivity*this.options.touchMultiplier;if(this.isModalOpen)this.preventScroll(t),this.options.debug;else if(Math.abs(s)>3||Math.abs(l)>3){var a=this.calculateCombinedDelta(s,l);this.addToScroll(a)}this.lastTouchX=o.clientX,this.lastTouchY=o.clientY,this.lastTouchTime=i,this.touchMoveCount++}else{var h=this;this.touchStopTimer||(this.touchStopTimer=setTimeout(function(){h.touchVelocityX*=.8,h.touchVelocityY*=.8,h.touchStopTimer=null},100))}}},n.prototype.onTouchEnd=function(t){if(!this.options.disabled){this.touchStopTimer&&(clearTimeout(this.touchStopTimer),this.touchStopTimer=null);var o=t.changedTouches[0],i=Date.now()-this.touchStartTime,e=this.touchStartY-o.clientY;if(i<300&&Math.abs(e)>50&&this.touchMoveCount>3){var n=400*this.touchVelocityY*(this.options.flingMultiplier||1);Math.abs(n)>50&&(this.addToScroll(n),this.options.debug)}this.touchVelocityX=0,this.touchVelocityY=0,this.touchMoveCount=0}},n.prototype.calculateCombinedDelta=function(t,o){if(this.options.useAngleBasedDirection){var i=this.options.horizontalAngleThreshold||20;this.options.prioritizeVertical&&(i=15);var e=Math.atan2(Math.abs(o),Math.abs(t))*(180/Math.PI);if(this.options.debug,e<=i)return t;var n=Math.sqrt(t*t+o*o);return this.touchDirectionLocked||(this.verticalScrollDirection=o>0?"down":"up",this.touchDirectionLocked=!0,this.options.debug),"down"===this.verticalScrollDirection?n:-n}if(this.options.lockTouchDirection){var r=this.options.touchDirectionThreshold||15,s=!1!==this.options.allowDirectionChange,l=this.options.directionChangeThreshold||25,a=this.options.directionChangeSmoothness||.3;if(this.smoothedDeltaX=this.smoothedDeltaX*(1-a)+t*a,this.smoothedDeltaY=this.smoothedDeltaY*(1-a)+o*a,!this.touchDirectionLocked&&(Math.abs(t)>r||Math.abs(o)>r)&&(this.options.prioritizeVertical?this.touchDirection=Math.abs(o)>5?"vertical":"horizontal":this.touchDirection=Math.abs(t)>Math.abs(o)?"horizontal":"vertical",this.touchDirectionLocked=!0,this.oppositeDirectionCount=0,this.options.debug),this.touchDirectionLocked&&s){var h="horizontal"===this.touchDirection,c=h?t:o,u=h?o:t;Math.abs(u)>Math.abs(c)&&Math.abs(u)>l?(this.oppositeDirectionCount++,1===this.oppositeDirectionCount&&(this.directionChangeStartTime=Date.now()),this.oppositeDirectionCount>=3&&(this.touchDirection=h?"vertical":"horizontal",this.oppositeDirectionCount=0,this.options.debug)):this.oppositeDirectionCount=Math.max(0,this.oppositeDirectionCount-.5);var d="horizontal"===this.touchDirection?this.smoothedDeltaX:this.smoothedDeltaY;if(0!==this.lastDeltaX||0!==this.lastDeltaY){var p="horizontal"===this.touchDirection?this.lastDeltaX:this.lastDeltaY;if(Math.abs(d-p)>50){var m=p+50*Math.sign(d-p);return this.lastDeltaX="horizontal"===this.touchDirection?m:t,this.lastDeltaY="vertical"===this.touchDirection?m:o,m}}return this.lastDeltaX=t,this.lastDeltaY=o,d}if(this.touchDirectionLocked)return"horizontal"===this.touchDirection?t:o}if(this.options.prioritizeVertical)return 0!==o?o:t;var v=Math.abs(t),b=Math.abs(o);if(v>.7*b)return t;if(b>.7*v)return o;n=Math.sqrt(t*t+o*o),e=Math.atan2(o,t);return Math.abs(e)<Math.PI/3||Math.abs(e)>2*Math.PI/3?t>0?n:-n:o>0?n:-n},n.prototype.pauseForModal=function(){this.isModalOpen=!0,this.savedScrollPosition=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,document.body&&(document.body.classList.add("twodimension-modal-open"),document.body.style.overflow="hidden",document.body.style.touchAction="none",document.body.style.top="-"+this.savedScrollPosition+"px"),document.documentElement&&(document.documentElement.style.overflow="hidden"),this.options.debug},n.prototype.resumeFromModal=function(){this.isModalOpen=!1,document.body&&(document.body.classList.remove("twodimension-modal-open"),document.body.style.overflow="",document.body.style.touchAction="",document.body.style.top=""),document.documentElement&&(document.documentElement.style.overflow=""),this.touchStartX=0,this.touchStartY=0,this.touchStartTime=0,this.lastTouchX=0,this.lastTouchY=0,this.lastTouchTime=0,this.touchVelocityX=0,this.touchVelocityY=0,this.touchMoveCount=0,this.touchStopTimer&&(clearTimeout(this.touchStopTimer),this.touchStopTimer=null),"number"==typeof this.savedScrollPosition&&(window.scrollTo(0,this.savedScrollPosition),this.targetScroll=this.savedScrollPosition,this.animatedScroll=this.savedScrollPosition),this.options.debug},n.prototype.isInModalMode=function(){return this.isModalOpen||!1},n.prototype.addToScroll=function(i){if(!isNaN(i)){(isNaN(this.targetScroll)||void 0===this.targetScroll)&&(this.targetScroll=0);var e=o(),n=this.targetScroll;this.targetScroll=t(this.targetScroll+i,0,e),isNaN(this.targetScroll)?this.targetScroll=n:(this.options.debug,Math.abs(this.targetScroll-n)>.1&&!this.rafId&&(this.options.debug,this.startAnimationLoop()))}},n.prototype.scrollTo=function(i,e){var n=o();this.targetScroll=t(i,0,n),e&&e.immediate&&(this.animatedScroll=this.targetScroll,window.scrollTo(0,this.animatedScroll)),!this.rafId&&Math.abs(this.targetScroll-this.animatedScroll)>.1&&this.startAnimationLoop()},n.prototype.on=function(t){this.scrollCallbacks.push(t)},n.prototype.off=function(t){var o=this.scrollCallbacks.indexOf(t);o>-1&&this.scrollCallbacks.splice(o,1)},n.prototype.disable=function(){this.options.disabled=!0},n.prototype.enable=function(){this.options.disabled=!1},n.prototype.showScrollbar=function(t){"boolean"==typeof t&&(this.options.ui.hideScrollbar=!t),this.setupScrollbarStyles()},n.prototype.toggleScrollbar=function(){this.options.ui.hideScrollbar=!this.options.ui.hideScrollbar,this.setupScrollbarStyles()},n.prototype.getScrollbarVisibility=function(){return{visible:!this.options.ui.hideScrollbar,hideScrollbar:this.options.ui.hideScrollbar}},n.prototype.isScrollbarVisible=function(){return!this.options.ui.hideScrollbar},n.prototype.getCurrentPosition=function(){return this.animatedScroll},n.prototype.getMaxPosition=function(){return o()},n.prototype.destroy=function(){this.touchStopTimer&&(clearTimeout(this.touchStopTimer),this.touchStopTimer=null),this.rafId&&(e(this.rafId),this.rafId=null),this.styleElement&&this.styleElement.parentNode&&(this.styleElement.parentNode.removeChild(this.styleElement),this.styleElement=null),this.scrollbarStyleElement&&this.scrollbarStyleElement.parentNode&&(this.scrollbarStyleElement.parentNode.removeChild(this.scrollbarStyleElement),this.scrollbarStyleElement=null);try{document.removeEventListener("wheel",this.preventScroll),document.removeEventListener("touchmove",this.preventScroll)}catch(t){}this.scrollCallbacks=[],this.targetScroll=0,this.animatedScroll=0,this.isScrolling=!1,this.isAnimating=!1,this.isModalOpen=!1},n.prototype.cleanup=function(){return this.destroy.bind(this)},n}function i(i={},e={}){const[n,r]=t.useState(!1),[s,l]=t.useState(0),[a,h]=t.useState({position:0,maxPosition:0,progress:0}),c=t.useRef(null);t.useEffect(()=>{const t=setTimeout(()=>{try{const t=o(),e={...{debug:!0,desktop:{duration:1e3,horizontalSensitivity:1.2,verticalSensitivity:1.5,lerp:.1,wheelMultiplier:1.1,precisionMode:!0,keyboardScrollAmount:.8},mobile:{duration:800,horizontalSensitivity:1.8,verticalSensitivity:2.2,lerp:.15,touchMultiplier:2.5,bounceEffect:!0,flingMultiplier:1.2,touchStopThreshold:4},tablet:{duration:900,horizontalSensitivity:1.5,verticalSensitivity:1.8,lerp:.12,wheelMultiplier:1.05,touchMultiplier:2.2,hybridMode:!0}},...i},n=new t(e);c.current=n;const s=t=>{l(t.scrollTop),h({position:t.scrollTop,maxPosition:n.getMaxPosition?.()||0,progress:n.getMaxPosition?.()>0?t.scrollTop/n.getMaxPosition()*100:0}),e.debug};n.on(s),r(!0)}catch(t){}},100);return()=>{clearTimeout(t),c.current&&c.current.cleanup?.()}},[]);return{isReady:n,scrollPosition:s,scrollInfo:a,scrollTo:t.useCallback(t=>{c.current&&c.current.scrollTo&&c.current.scrollTo(t)},[]),instance:c.current}}exports.default=i,exports.useTwoDimensionScroll=i;