UNPKG

aero-slider

Version:

A lightweight, CSS-first slider library for the modern web

3 lines (2 loc) • 17.1 kB
/*! Aero Slider v1.0.0-beta.13 | https://github.com/Negative-Space-Dev/aero-slider */ function Ge(n){let{container:d,signal:t}=n,i=d.querySelector(".aero-slider__nav--prev"),S=d.querySelector(".aero-slider__nav--next");return i?.addEventListener("click",n.prev,{signal:t}),S?.addEventListener("click",n.next,{signal:t}),{refresh(){let f=n.maxIndex()===0,m=!n.loop();if(i)i.disabled=f||m&&n.current()===0;if(S)S.disabled=f||m&&n.current()>=n.maxIndex()}}}function Ke(n){let d=n.container.querySelector(".aero-slider__pagination"),t=d?.querySelector(".aero-slider__dot");if(!d||!t)return{build(){},refresh(){}};return vt(n,d,t)}function vt(n,d,t){let{config:i,signal:S}=n,f=[],m=!1,u=null,l=0;function c(){for(let p of f)if(p!==t)p.remove();u?.remove(),u=null,f=[],t.style.display="",d.classList.remove("aero-slider__pagination--windowed"),d.style.removeProperty("--pagination-width")}function w(){c();let p=n.pageCount(),{maxDots:M}=i;if(m=M>0&&p>M,m)u=document.createElement("div"),u.className="aero-slider__pagination-track";let h=u??d;for(let T=0;T<p;T++){let A=!m&&T===0?t:t.cloneNode(!0);if(A.setAttribute("role","tab"),A.setAttribute("aria-label",`Go to slide ${T+1}`),A.dataset.slideIndex=String(T),A!==t)h.append(A);f.push(A)}if(u){t.style.display="none",d.classList.add("aero-slider__pagination--windowed"),d.append(u),l=f[1].offsetLeft-f[0].offsetLeft;let T=(M-1)*Math.abs(l)+f[0].offsetWidth;d.style.setProperty("--pagination-width",`${T}px`)}g()}function g(){let p=n.current(),M=f.length,{maxDots:h}=i,T=m?Math.max(0,Math.min(p-Math.floor(h/2),M-h)):0,A=T===0,K=T>=M-h;u?.style.setProperty("--track-offset",`${-T*l}px`),f.forEach((v,q)=>{let z=q===p;if(v.classList.toggle("aero-slider__dot--active",z),v.setAttribute("aria-selected",String(z)),!m)return;let _=q-T,D=_<0||_>=h?"hidden":_===0&&!A||_===h-1&&!K?"edge":_===1&&!A||_===h-2&&!K?"near-edge":"";if(v.classList.remove("aero-slider__dot--hidden","aero-slider__dot--edge","aero-slider__dot--near-edge"),D)v.classList.add(`aero-slider__dot--${D}`)})}return d.setAttribute("role","tablist"),d.addEventListener("click",(p)=>{let M=p.target.closest(".aero-slider__dot");if(M?.dataset.slideIndex)n.goTo(Number(M.dataset.slideIndex))},{signal:S}),S.addEventListener("abort",c),{build:w,refresh:g}}function Ue(n){let{container:d,signal:t}=n;if(!d.hasAttribute("tabindex"))d.tabIndex=0,t.addEventListener("abort",()=>d.removeAttribute("tabindex"));d.addEventListener("keydown",(i)=>{if(i.target.closest("input, textarea, select, [contenteditable]"))return;let{direction:S}=n.config,[f,m]=S==="ttb"?["ArrowUp","ArrowDown"]:S==="rtl"?["ArrowRight","ArrowLeft"]:["ArrowLeft","ArrowRight"];if(i.key===f)n.prev();else if(i.key===m)n.next();else return;i.preventDefault()},{signal:t})}var bt=150;function Xe(n){let{container:d,track:t,config:i,signal:S,reducedMotion:f}=n,m=new Set,u=()=>i.autoplay==="continuous",l=0,c=null,w=!1,g=0,p=new Set,M=()=>S.aborted||!i.autoplay||m.size>0||document.hidden||f.matches||u()&&!(i.autoplaySpeed>0);function h(){if(n.easing())return;if(!n.loop()&&n.current()>=n.maxIndex())n.goTo(0);else n.next()}function T(s,{start:L,width:b}){while(s<L)s+=b;while(s>=L+b)s-=b;return s}function A(s){return(Number(s.animations[0]?.currentTime)||0)%s.duration/s.duration*s.width}function K(){let s=n.cycle();if(!s)return;let L=T(n.position(),s);if(L+s.width>n.maxScroll())return;if(Math.abs(L-n.position())>0.5)n.jumpTo(L);let b=(n.isRtl()?1:-1)*s.width,P=n.isVertical()?`0 ${b}px`:`${b}px 0`,H=s.width/i.autoplaySpeed*1000,U=document.timeline.currentTime,j=Array.from(t.children,(ae)=>{let y=ae.animate([{translate:"0 0"},{translate:P}],{duration:H,iterations:1/0});return y.startTime=U,y});if(c={...s,duration:H,animations:j},!w)w=!0,n.emit("autoplayStart",{})}function v(s,L=!0){if(!c)return;let b=c;c=null;let P=s?n.position()+A(b):null;for(let H of b.animations)H.cancel();if(P!==null)n.jumpTo(P);if(L&&w)w=!1,n.emit("autoplayStop",{})}function q(){if(M()){if(w&&!c)w=!1,n.emit("autoplayStop",{});return}if(u()){if(!c)K()}else if(!l)l=window.setInterval(h,i.autoplayInterval),n.emit("autoplayStart",{})}function z(){if(!l)return;clearInterval(l),l=0,n.emit("autoplayStop",{})}function _(){z(),v(!0)}function D(s){m.add(s),_()}function O(s){m.delete(s),q()}function V(){D("settle"),clearTimeout(g),g=window.setTimeout(()=>O("settle"),bt)}let C=(s,L,b)=>s.addEventListener(L,b,{passive:!0,signal:S});C(d,"pointerenter",()=>!u()&&D("pointer")),C(d,"pointerleave",()=>O("pointer")),C(t,"pointerdown",(s)=>{if(!i.autoplay)return;p.add(s.pointerId),D("press")});let X=(s)=>{if(s.type==="dragend"||s.type==="pointermove"){if(!p.size||s.buttons)return;p.clear()}else if(!p.delete(s.pointerId)||p.size)return;m.delete("press"),V()};for(let s of["pointerup","pointercancel","pointermove","dragend"])addEventListener(s,X,{capture:!0,passive:!0,signal:S});return C(d,"focusin",(s)=>{if(s.target.matches(":focus-visible"))D("focus")}),C(d,"focusout",(s)=>{if(!d.contains(s.relatedTarget))O("focus")}),C(d,"aero:slideChange",(s)=>{if(s.target!==d||!l)return;clearInterval(l),l=window.setInterval(h,i.autoplayInterval)}),C(document,"visibilitychange",()=>document.hidden?_():q()),C(f,"change",()=>f.matches?_():q()),S.addEventListener("abort",()=>{clearTimeout(g),z(),v(!1)}),{start:q,stop:_,hold:D,release:O,drifting:()=>c!==null,reset(){v(!1,!1)},interrupt(){if(!c)return!1;return V(),!0},scrolled(){if(m.has("settle"))clearTimeout(g);if(c){let s=n.position(),L=c.width/n.pageCount();if(s+A(c)>n.maxScroll()-L)n.jumpTo(s-c.width)}},settled(){if(clearTimeout(g),m.has("settle"))O("settle")}}}var ue="data-aero-slider-index",He="data-aero-slider-clone",ht=(n)=>1-(1-n)**3,Et={loop:!1,autoplay:!1,autoplayInterval:5000,autoplaySpeed:40,draggable:!0,alignment:"center",maxDots:0,noDrag:"",perMove:1,direction:"ltr",snap:"native",scrollDuration:0,scrollEasing:ht},St=5,yt=0.3,Ye=250,Tt=150,Je=200;function Lt(n){let d=n.querySelector(".aero-slider__track");if(!d)throw Error("aero-slider: missing .aero-slider__track");if(!d.children.length)throw Error("aero-slider: no slides found");return d}function Qe(n,d={}){let t=Lt(n),i={...Et,...d},S=new AbortController,{signal:f}=S,m=[],u=0,l=0,c=!1,w=1,g=0,p=0,M=0,h=0,T=0,A=0,K=matchMedia("(prefers-reduced-motion: reduce)"),v=!1,q=0,z=!1,_=!1,D=0,O=0,V=0,C=!1,X=new Set,s=new Set,L=!1,b=()=>i.direction==="ttb",P=()=>i.direction==="rtl",H=(e,r,o)=>Math.max(r,Math.min(e,o)),U=(e)=>(e%u+u)%u;function j(){let e=i.alignment==="left"&&Number.isInteger(w);return Math.max(0,e?u-w:u-1)}let ae=()=>i.autoplay==="continuous",y=()=>ae()?u>1:i.loop&&j()>0,fe=()=>ae()?"none":i.snap,ye=()=>y()?u:j()+1,ke=()=>!y()?0:ae()?u+Math.ceil(w)+2:Math.max(u,Math.ceil(w)+2);function N(e,r){n.dispatchEvent(new CustomEvent(`aero:${e}`,{detail:r,bubbles:!0}))}function E(){if(b())return t.scrollTop;return P()?-t.scrollLeft:t.scrollLeft}function Te(e,r){if(b())t.scrollTo({top:e,behavior:r});else t.scrollTo({left:P()?-e:e,behavior:r})}function me(){if(!V)return;cancelAnimationFrame(V),V=0,t.style.scrollSnapType=""}function B(e,r=!1){if(me(),!r||K.matches)return Te(e,"instant");if(i.scrollDuration<=0)return Te(e,"smooth");let o=E(),a=e-o,k=performance.now();t.style.scrollSnapType="none";let x=(F)=>{let W=Math.min(1,Math.max(0,(F-k)/i.scrollDuration));if(Te(o+a*i.scrollEasing(W),"instant"),V=W<1?requestAnimationFrame(x):0,!V)t.style.scrollSnapType=""};V=requestAnimationFrame(x)}function R(e){let r=e.getBoundingClientRect(),o=t.getBoundingClientRect(),[a,k,x,F]=b()?[o.top+t.clientTop,t.clientHeight,r.top,r.bottom]:P()?[-(o.left+t.clientLeft+t.clientWidth),t.clientWidth,-r.right,-r.left]:[o.left+t.clientLeft,t.clientWidth,r.left,r.right],W=a+T,de=a+k-A,ce=i.alignment==="left"?x-W:i.alignment==="right"?F-de:(x+F-W-de)/2;return E()+ce}function De(){let e=getComputedStyle(n).getPropertyValue("--slides-per-view");w=parseFloat(e)||1}function Oe(){let e=getComputedStyle(t);if(b())T=parseFloat(e.paddingTop),A=parseFloat(e.paddingBottom);else T=parseFloat(P()?e.paddingRight:e.paddingLeft),A=parseFloat(P()?e.paddingLeft:e.paddingRight);let[r,o]=t.children,a=b()?t.clientHeight:t.clientWidth;M=r?R(r):0,p=o?R(o)-M:a,h=b()?t.scrollHeight-t.clientHeight:t.scrollWidth-t.clientWidth}let J=(e)=>Math.round((e-M)/p),Pe=(e)=>e>=g&&e<g+u,te=(e)=>y()?U(e-g):H(e,0,j());function pe(e){if(!y()){if(e<=1)return 0;if(e>=h-1)return j()}return te(J(e))}function le(e){let r=R(t.children[g+e]);return y()?r:H(r,0,h)}function ne(e){if(e===l)return;l=e,N("slideChange",{index:e}),Ie.refresh(),Ce.refresh()}function Le(e){let r=t.children[e],o=t.children[g+U(e-g)];return r&&o?R(o)-R(r):0}function Re(){if(!y())return;let e=J(E());if(!Pe(e))B(E()+Le(e))}function xe(){let e=t.children[g],r=t.children[g+u];return e&&r?R(r)-R(e):0}function ge(e,r=!0){v=!0,q=H(e,0,h),B(q,r)}function Fe(e){let r=e.cloneNode(!0);r.removeAttribute(ue),r.setAttribute(He,""),r.setAttribute("aria-hidden","true");for(let a of[r,...r.querySelectorAll("[id]")])a.removeAttribute("id");let o="a, button, input, select, textarea, [tabindex]";for(let a of[r,...r.querySelectorAll(o)])if(a.matches(o))a.tabIndex=-1;return r}function ve(e,r={}){if(c||!u)return;I.interrupt();let o=y()?U(Math.trunc(e)):H(Math.trunc(e),0,j());if(ne(o),!p)return;let a;if(y()){Re();let k=J(E()),x=U(o-te(k)),F=x>u/2?x-u:x;a=R(t.children[k+F])}else a=le(o);if(Math.abs(a-E())<1){if(v)B(a);return v=!1,re()}ge(a,!r.instant)}let qe=()=>Math.max(1,Math.trunc(i.perMove));function ze(e){if(I.interrupt())ne(pe(E()));ve(l+e)}let Ne=()=>ze(qe()),Be=()=>ze(-qe());function tt(){if(I.scrolled(),!v&&!D)D=requestAnimationFrame(()=>{if(D=0,!v)ne(pe(E()))});if(!("onscrollend"in t)||C)clearTimeout(O),O=window.setTimeout(re,C?Je:Tt)}function re(){if(z)return;if(clearTimeout(O),C=!1,X.size||s.size){L=!0;return}if(v&&Math.abs(E()-q)>1)return;let e=!v;if(v=!1,t.style.scrollSnapType="",e&&fe()==="settle"&&We(E()))return;Re();let r=E(),o=pe(r),a=y()||Math.abs(r-le(l))>1;if(o!==l&&a)ne(o);I.settled()}function nt(e){let r=R(t.children[e]);if(r<-1||r>h+1){let o=Le(e);B(E()+o),r+=o}ne(te(e)),ge(r)}function We(e){if(!p)return!1;if(!y()){let o=pe(H(e,0,h)),a=le(o);if(Math.abs(a-E())<=1)return!1;return ne(o),ge(a),!0}let r=H(J(e),0,t.children.length-1);if(Math.abs(R(t.children[r])-E())<=1)return!1;return nt(r),!0}function rt(e){let r=e*Ye;if(!y())return r;let o=Math.max(0,xe()-p);return H(r,-o,o)}function ot(e){if(_=!1,v=!1,e.pointerType!=="touch")X.add(e.pointerId);if(C)L=!0;if(C=!1,clearTimeout(O),me(),!i.draggable||e.button!==0||e.pointerType==="touch")return;if(i.noDrag&&e.target.closest(i.noDrag))return;let r=b()?"clientY":"clientX",o=P()?-1:1,a=e[r],k=l,x=new AbortController,F=E(),W=F,de=a,ce=e.timeStamp,Y=0,ie=0;function gt(se){let Q=se[r];if(!z){if(Math.abs(Q-a)<St)return;z=!0,_=!0,t.setPointerCapture(se.pointerId),t.style.scrollSnapType="none",n.classList.add("aero-slider--dragging"),I.hold("drag"),N("dragStart",{index:k})}let Z=se.timeStamp-ce;if(Z>0){let ee=(de-Q)*o/Z;Y=Z<100?0.3*ee+0.7*Y:Y/2,de=Q,ce=se.timeStamp}if(W=F+(a-Q)*o,y()){let ee=J(W);if(!Pe(ee)){let G=Le(ee);W+=G,F+=G}}if(!ie)ie=requestAnimationFrame(()=>{ie=0,B(W)})}function $e(se){if(x.abort(),!z)return;if(z=!1,n.classList.remove("aero-slider--dragging"),ie)cancelAnimationFrame(ie),ie=0,B(W);let Q=se.timeStamp-ce;if(Q>50)Y*=Math.max(0,1-Q/200);if(fe()!=="native"){let ee=E(),G=ee+rt(Y);if(fe()==="settle"){if(!We(G))re()}else{if(y()&&(G<0||G>h)){let je=G>h?-xe():xe();B(ee+je),G+=je}if(Math.abs(G-E())>1)ge(G);else re()}N("dragEnd",{index:l,fromIndex:k}),I.release("drag");return}let Z=J(E()+Y*Ye);if(Math.abs(Y)>yt&&Z===J(E()))Z+=Math.sign(Y);ve(te(Z)),N("dragEnd",{index:l,fromIndex:k}),I.release("drag")}let Se={signal:x.signal};t.addEventListener("pointermove",gt,Se),t.addEventListener("pointerup",$e,Se),t.addEventListener("pointercancel",$e,Se),f.addEventListener("abort",()=>x.abort(),Se)}function it(e){if(!_)return;_=!1,e.preventDefault(),e.stopPropagation()}let we=!1,be=new ResizeObserver(()=>{if(we){we=!1;return}if(c)return;N("resize",{}),lt(),N("resized",{})}),he,Me=new Map,Ae=new Set;function st(e){for(let a of e)Me.set(a.target,a.isIntersecting);let r=Array.from(t.children),o=new Set;for(let[a,k]of Me)if(k)o.add(te(r.indexOf(a)));for(let a of Ae)if(!o.has(a))N("hidden",{index:a});for(let a of o)if(!Ae.has(a))N("visible",{index:a});Ae=o}function at(){if(be.disconnect(),we=!0,be.observe(t),t.firstElementChild)be.observe(t.firstElementChild);he?.disconnect(),Me.clear(),he=new IntersectionObserver(st,{root:t,rootMargin:b()?"-1px 0px":"0px -1px"});for(let e of t.children)he.observe(e)}function lt(){let e=ye();if(I.drifting()){let r=Array.from(t.children),o=E(),a=(x)=>Math.abs(R(x)-o),k=r.reduce((x,F)=>a(F)<a(x)?F:x);l=te(r.indexOf(k))}if(I.reset(),De(),ke()!==g)return oe();if(Oe(),ye()!==e)Ie.build();l=y()?U(l):H(l,0,j()),v=!1,B(le(l)),Ce.refresh(),I.start()}function oe(){I.reset();for(let e of t.querySelectorAll(`[${He}]`))e.remove();if(m=Array.from(t.children),u=m.length,!u)return;if(m.forEach((e,r)=>{e.classList.add("aero-slider__slide"),e.setAttribute(ue,String(r))}),n.classList.toggle("aero-slider--vertical",b()),P())n.setAttribute("dir","rtl");else n.removeAttribute("dir");n.setAttribute("data-aero-alignment",i.alignment),n.classList.toggle("aero-slider--draggable",i.draggable),n.classList.toggle("aero-slider--free",fe()!=="native"),De(),g=ke();for(let e=1;e<=g;e++)t.prepend(Fe(m[U(-e)]));for(let e=0;e<g;e++)t.append(Fe(m[e%u]));Oe(),l=y()?U(l):H(l,0,j()),v=!1,B(le(l)),Ie.build(),Ce.refresh(),at(),I.stop(),I.start()}function dt(e){if(c)return;Object.assign(i,e),oe()}function ct(){if(!c)oe()}function ut(e,r){if(c)return;let o=r===void 0?null:m[r]??null;for(let a of[].concat(e))t.insertBefore(a,o);oe()}function ft(e){if(c)return;for(let r of[].concat(e))m[r]?.remove();oe()}function mt(){if(c)return;N("destroy",{}),c=!0,S.abort(),be.disconnect(),he?.disconnect(),clearTimeout(O),cancelAnimationFrame(D),me();for(let e of t.querySelectorAll(`[${He}]`))e.remove();t.style.scrollSnapType="",n.classList.remove("aero-slider--dragging","aero-slider--draggable","aero-slider--free","aero-slider--vertical","aero-slider--ready");for(let e of["aria-roledescription","dir","data-aero-alignment"])n.removeAttribute(e);if(n.aeroSlider===_e)delete n.aeroSlider}let _e={get element(){return n},get currentIndex(){return l},get slideCount(){return u},next:Ne,prev:Be,goTo:ve,pause:()=>I.hold("api"),resume:()=>I.release("api"),update:dt,refresh:ct,add:ut,remove:ft,destroy:mt},Ee={container:n,track:t,config:i,signal:f,reducedMotion:K,easing:()=>V!==0,current:()=>l,maxIndex:j,pageCount:ye,loop:y,next:Ne,prev:Be,goTo:ve,emit:N,isVertical:b,isRtl:P,position:E,maxScroll:()=>h,jumpTo:(e)=>B(e),cycle(){if(!y()||!p)return null;let e=t.children[g],r=t.children[g+u];if(!e||!r)return null;let o=R(e),a=R(r)-o;return a>0?{start:o-p/2,width:a}:null}},Ce=Ge(Ee),Ie=Ke(Ee),I=Xe(Ee);Ue(Ee),n.removeAttribute("data-aero-defer-visibility"),n.classList.add("aero-slider"),n.setAttribute("aria-roledescription","carousel"),t.classList.add("aero-slider__track"),t.addEventListener("scroll",tt,{passive:!0,signal:f}),K.addEventListener("change",()=>K.matches&&v&&B(q),{signal:f}),t.addEventListener("scrollend",re,{signal:f}),t.addEventListener("wheel",()=>{v=!1,C=!0,me()},{passive:!0,signal:f}),t.addEventListener("pointerdown",ot,{signal:f});let Ve=(e)=>{if(e.type.startsWith("touch"))for(let r of e.changedTouches)s.delete(r.identifier);else if(e.type==="dragend"||e.type==="pointermove"){if(!X.size||e.buttons)return;X.clear()}else if(!X.delete(e.pointerId))return;if(X.size||s.size||!L)return;L=!1,C=!0,clearTimeout(O),O=window.setTimeout(re,Je)};addEventListener("touchstart",(e)=>{let r=e.target;if(!t.contains(r))return;for(let o of e.changedTouches)s.add(o.identifier);for(let o of["touchend","touchcancel"])r.addEventListener(o,Ve,{once:!0,passive:!0,signal:f})},{capture:!0,passive:!0,signal:f});let pt=["pointerup","pointercancel","pointermove","dragend","touchend","touchcancel"];for(let e of pt)addEventListener(e,Ve,{capture:!0,passive:!0,signal:f});return t.addEventListener("click",it,{capture:!0,signal:f}),t.addEventListener("dragstart",(e)=>i.draggable&&e.preventDefault(),{signal:f}),oe(),n.aeroSlider=_e,n.classList.add("aero-slider--ready"),N("ready",{}),_e}var Ze="aero-slider__thumb--active";function et(n,d,t={}){let i=d.element.querySelector(".aero-slider__track");if(!i)return()=>{};let S=new AbortController,{signal:f}=S;d.update({draggable:!1,loop:t.loop??!0}),i.style.cursor="pointer";let m=(l)=>{let c=l.getAttribute(ue);if(c!==null)return Number(c);let w=Array.from(i.children),g=w.findIndex((M)=>M.hasAttribute(ue)),p=d.slideCount;return((w.indexOf(l)-g)%p+p)%p},u=(l)=>{for(let c of i.children)c.classList.toggle(Ze,m(c)===l);d.goTo(l)};return i.addEventListener("click",(l)=>{let c=l.target;while(c&&c.parentElement!==i)c=c.parentElement;if(c)n.goTo(m(c))},{signal:f}),n.element.addEventListener("aero:slideChange",(l)=>u(l.detail.index),{signal:f}),u(n.currentIndex),()=>{S.abort(),i.style.cursor="";for(let l of i.children)l.classList.remove(Ze)}}if(typeof window<"u")window.AeroSlider={createSlider:Qe,syncThumbnails:et};export{Qe as createSlider,et as syncThumbnails};