Skip to content

Instantly share code, notes, and snippets.

@Arifursdev
Last active May 13, 2025 16:03
Show Gist options
  • Save Arifursdev/c89ad079d764577bcd3f7a1722440f1c to your computer and use it in GitHub Desktop.
Save Arifursdev/c89ad079d764577bcd3f7a1722440f1c to your computer and use it in GitHub Desktop.
class AdevScrollState {
constructor(element) {
this.scrollableEl = this.selectElement(element);
if (this.scrollableEl === null) return console.error("AdevScrollState: Element not found");
this.isScrollable = false;
this.isScrolled = false;
this.isAtTop = false;
this.isAtBottom = false;
this.isAtLeft = false;
this.isAtRight = false;
this.updateScrollState();
window.addEventListener('resize', () => this.updateScrollState());
this.scrollableEl.addEventListener('scroll', () => this.updateScrollState());
// Add event listeners for grabbing
this.scrollableEl.addEventListener('mousedown', () => this.addGrabbingClass());
this.scrollableEl.addEventListener('mouseup', () => this.removeGrabbingClass());
this.scrollableEl.addEventListener('mouseleave', () => this.removeGrabbingClass());
}
selectElement(element) {
return typeof element === "string" ? document.querySelector(element) : element instanceof Element ? element : null
}
updateScrollState() {
const scrollTop = this.scrollableEl.scrollTop;
const scrollLeft = this.scrollableEl.scrollLeft;
const scrollHeight = this.scrollableEl.scrollHeight;
const scrollWidth = this.scrollableEl.scrollWidth;
const clientHeight = this.scrollableEl.clientHeight;
const clientWidth = this.scrollableEl.clientWidth;
this.isScrollable = scrollHeight > clientHeight || scrollWidth > clientWidth;
this.isScrolled = scrollTop > 0 || scrollLeft > 0;
this.isAtTop = scrollTop === 0;
this.isAtBottom = scrollTop + clientHeight === scrollHeight;
this.isAtLeft = scrollLeft === 0;
this.isAtRight = scrollLeft + clientWidth === scrollWidth;
let classes = [];
if (this.isScrollable) classes.push('adev--scrollable');
if (this.isScrolled) classes.push('adev--scrolled');
if (!this.isAtTop) classes.push('adev--scrollable-top');
if (!this.isAtBottom) classes.push('adev--scrollable-bottom');
if (!this.isAtLeft) classes.push('adev--scrollable-left');
if (!this.isAtRight) classes.push('adev--scrollable-right');
this.scrollableEl.classList.remove('adev--scrollable', 'adev--scrolled', 'adev--scrollable-top', 'adev--scrollable-bottom', 'adev--scrollable-left', 'adev--scrollable-right');
this.scrollableEl.classList.add(...classes);
}
addGrabbingClass() {
this.scrollableEl.classList.add('adev--grabbing');
}
removeGrabbingClass() {
this.scrollableEl.classList.remove('adev--grabbing');
}
}
document.addEventListener('adev:init:scrollable:state', function () {
document.querySelectorAll('[data-adev-scrollable-state]:not(.adev-initialized)').forEach(function (element) {
element.classList.add('adev-initialized');
new AdevScrollState(element);
});
});
document.dispatchEvent(new CustomEvent('adev:init:scrollable:state'));
// minified:
class AdevScrollState{constructor(l){if(this.scrollableEl=this.selectElement(l),null===this.scrollableEl)return console.error("AdevScrollState: Element not found");this.isScrollable=!1,this.isScrolled=!1,this.isAtTop=!1,this.isAtBottom=!1,this.isAtLeft=!1,this.isAtRight=!1,this.updateScrollState(),window.addEventListener("resize",(()=>this.updateScrollState())),this.scrollableEl.addEventListener("scroll",(()=>this.updateScrollState())),this.scrollableEl.addEventListener("mousedown",(()=>this.addGrabbingClass())),this.scrollableEl.addEventListener("mouseup",(()=>this.removeGrabbingClass())),this.scrollableEl.addEventListener("mouseleave",(()=>this.removeGrabbingClass()))}selectElement(l){return"string"==typeof l?document.querySelector(l):l instanceof Element?l:null}updateScrollState(){const l=this.scrollableEl.scrollTop,t=this.scrollableEl.scrollLeft,e=this.scrollableEl.scrollHeight,s=this.scrollableEl.scrollWidth,i=this.scrollableEl.clientHeight,a=this.scrollableEl.clientWidth;this.isScrollable=e>i||s>a,this.isScrolled=l>0||t>0,this.isAtTop=0===l,this.isAtBottom=l+i===e,this.isAtLeft=0===t,this.isAtRight=t+a===s;let o=[];this.isScrollable&&o.push("adev--scrollable"),this.isScrolled&&o.push("adev--scrolled"),this.isAtTop||o.push("adev--scrollable-top"),this.isAtBottom||o.push("adev--scrollable-bottom"),this.isAtLeft||o.push("adev--scrollable-left"),this.isAtRight||o.push("adev--scrollable-right"),this.scrollableEl.classList.remove("adev--scrollable","adev--scrolled","adev--scrollable-top","adev--scrollable-bottom","adev--scrollable-left","adev--scrollable-right"),this.scrollableEl.classList.add(...o)}addGrabbingClass(){this.scrollableEl.classList.add("adev--grabbing")}removeGrabbingClass(){this.scrollableEl.classList.remove("adev--grabbing")}}document.addEventListener("adev:init:scrollable:state",(function(){document.querySelectorAll("[data-adev-scrollable-state]:not(.adev-initialized)").forEach((function(l){l.classList.add("adev-initialized"),new AdevScrollState(l)}))})),document.dispatchEvent(new CustomEvent("adev:init:scrollable:state"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment