vue-directional-carousel
Version:
This is a Vue 3 component that allows you to set the direction of image movement not only vertically and horizontally but also in different directions (left, right, up, down).
2 lines (1 loc) • 14.6 kB
JavaScript
(function(e,E){typeof exports=="object"&&typeof module<"u"?module.exports=E(require("vue")):typeof define=="function"&&define.amd?define(["vue"],E):(e=typeof globalThis<"u"?globalThis:e||self,e.VueDirectionalCarousel=E(e.Vue))})(this,function(e){"use strict";const E=A=>{var r;const i=[];(r=A.items)!=null&&r.length||i.push({prop:"items",message:"At least one item is required"}),A.interval!=null&&A.interval<0&&i.push({prop:"interval",message:"Interval must be a non-negative number"}),A.duration!=null&&A.duration<=0&&i.push({prop:"duration",message:"Duration must be greater than 0"});const o=/^(\d+(\.\d+)?)(px|%|rem|em|vh|vw)$/;return A.width&&!o.test(A.width)&&i.push({prop:"width",message:"Width must be a valid CSS dimension (e.g., 100%, 200px)"}),A.height&&!o.test(A.height)&&i.push({prop:"height",message:"Height must be a valid CSS dimension (e.g., 300px, 50vh)"}),i},P={style:{padding:"0px 4px 0px 4px"}},H=["onClick","aria-label","aria-current"],R=e.defineComponent({__name:"DotButtons",props:{currentIndex:{default:0},itemCount:{default:0},showDots:{type:Boolean,default:!1}},emits:["click-dot-button"],setup(A,{emit:i}){const o=i,r=A,d=e.ref({display:"flex",alignItems:"center",justifyContent:"center",flexWrap:"wrap"}),s=u=>{o("click-dot-button",u-1)},l=e.computed(()=>new Array(r.itemCount).fill({border:"none",borderRadius:"50%",backgroundColor:"gray",cursor:"pointer"}).map((u,t)=>{const a=t===(r.itemCount>r.currentIndex?r.currentIndex:0);return{...u,opacity:a?"1":"0.5",height:a?"8px":"6px",paddingInline:a?"4px":"3px"}}));return(u,t)=>(e.openBlock(),e.createElementBlock("div",{style:e.normalizeStyle(d.value)},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(u.itemCount,a=>(e.openBlock(),e.createElementBlock("div",P,[e.createElementVNode("button",{type:"button",style:e.normalizeStyle(l.value[a-1]),onClick:m=>s(a),"aria-label":`Go to slide ${a}`,"aria-current":a-1===u.currentIndex},null,12,H)]))),256))],4))}});function D(){const A=e.ref({zIndex:1,display:"flex",justifyContent:"center",alignItems:"center",padding:"5px"}),i=e.ref({height:"20px",border:"none",color:"silver",borderRadius:"10px"});return{buttonWrapperStyle:A,buttonStyle:i,onMouseDownButton:()=>{i.value.color="gray"},onMouseUpButton:()=>{i.value.color="silver"}}}const S="data:image/png;base64,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pr/pb/qb/qa/6W/6m/42U1utv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7662+vZv8J/fXXX3/99ddff/31119//fXXX3/99ddff/2buDX666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//qa/6W/6m/6mv+lv+pv+pr/pb/rbjG2t/vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//rOz/z399ddff/31119//fXXX3/99ddff/31119//fXXX3/99ddff/31119//fXXX3/9Z+PW6a+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vrrr7/++uuvv/7666+//vqb/qa/6W/6m/6mv+lv+pv+pr/N6Lr1119//fXXX/+4ef5n9pbc0T9586/qH73T+kfvoP7R63uif/IW39c/esf1j17XlP5+AtA/dque6h+9i/pHr1v/7B3TP3u39I/eCv2z96X+2WvpH723pvSP3hb9s7dH/+wd1j97Q/pn70f9szesf/bG9M/ebf2zd03/7F3SP3sn9M9ev/7Z269/9rbrn71l+odvVP/sDeifvV79s9cxrn/2TumfvR36h78G3NA/e9v0z97cEf2zt0n/8LX0z16P/uHr1z/8+8Dz+mdvwaj+2Vt+V//sbXisf/b2ti1gss/VGvV+0ER7/cdWulmz1tXWr4Vai1ysaVvYxlNjhzrdq3mbd2Sa+R/tc6xmbv20Hhhwwct/c7f1+ktf/XtcqdGvAztf+PjgkY1O1PR17j43+fz64ye995OxNzZ/+9ez9UcHejtcJmgffPrV4Nkrfzy4f7N15uiBXUtdZCb2HyDq9i+SDCuqAAAAAElFTkSuQmCC",T=["src"],L=e.defineComponent({__name:"PrevButton",emits:["click-prev-button"],setup(A,{emit:i}){const o=i,{buttonWrapperStyle:r,buttonStyle:d,onMouseDownButton:s}=D(),l=()=>{o("click-prev-button")};return(u,t)=>(e.openBlock(),e.createElementBlock("div",{style:e.normalizeStyle(e.unref(r))},[e.createElementVNode("button",{type:"button",class:"prev-button",style:e.normalizeStyle(e.unref(d)),onClick:l,onMousedown:t[0]||(t[0]=(...a)=>e.unref(s)&&e.unref(s)(...a)),"aria-label":"Previous slide"},[e.createElementVNode("img",{alt:"left arrow",src:e.unref(S),style:{width:"10px",borderRadius:"50%",transform:"scaleX(-1)"}},null,8,T)],36)],4))}}),M=["src"],O=e.defineComponent({__name:"NextButton",emits:["click-next-button"],setup(A,{emit:i}){const o=i,{buttonWrapperStyle:r,buttonStyle:d,onMouseUpButton:s}=D(),l=()=>{o("click-next-button")};return(u,t)=>(e.openBlock(),e.createElementBlock("div",{style:e.normalizeStyle(e.unref(r))},[e.createElementVNode("button",{type:"button",class:"next-button",style:e.normalizeStyle(e.unref(d)),onClick:l,onMouseup:t[0]||(t[0]=(...a)=>e.unref(s)&&e.unref(s)(...a)),"aria-label":"Next slide"},[e.createElementVNode("img",{alt:"left arrow",src:e.unref(S),style:{width:"10px",borderRadius:"3px"}},null,8,M)],36)],4))}}),W=1e3,q="translate";function F(A,i,o,r,d){const s=e.ref(!1),l=e.computed(()=>{const B=A.direction;return{isHorizontal:["left","right"].includes(B),isReverse:["up","left"].includes(B),flexDirection:{left:"row",right:"row-reverse",up:"column",down:"column-reverse"}[B]}}),u=e.computed(()=>l.value.isHorizontal?r.value:d.value),t=e.computed(()=>{const B=i.value.length,v=o.value%B;return l.value.isReverse?v:B-(v+1%B)}),a=e.computed(()=>t.value*u.value),m=e.computed(()=>{const B=l.value.isHorizontal?"X":"Y";return`${q}${B}(-${a.value}px)`}),p=e.ref(`transform ${(A.duration??W)/1e3}s ease`),g=e.ref(p.value);return{itemsTranslate:m,defaultTransition:p,transition:g,isTransitioning:s,directionProps:l}}function j(A,i,o,r,d,s,l){const u=e.ref(null),t=e.ref(!1),a=()=>{r.value=++r.value%o.value.length,s.value=d.value},m=()=>{l.value||(r.value>=o.value.length-1?(l.value=!0,s.value="",r.value=0,requestAnimationFrame(()=>{requestAnimationFrame(()=>{s.value=d.value,r.value=1,setTimeout(()=>{l.value=!1},A.duration||1e3)})})):a())},p=()=>{u.value!==null&&(window.clearInterval(u.value),u.value=null)},g=()=>{p(),A.interval&&A.items.length>1&&!t.value&&(u.value=window.setInterval(m,A.interval))},B=()=>{m(),A.interval&&A.items.length>1&&g()},v=e.computed(()=>(r.value-1+o.value.length)%o.value.length),h=()=>{l.value||(r.value===0?(l.value=!0,s.value="",r.value=v.value,setTimeout(()=>{r.value=v.value,s.value=d.value,setTimeout(()=>{l.value=!1},A.duration||1e3)},100)):r.value=v.value,A.interval&&A.items.length>1&&g())},w=b=>{l.value||(r.value=b,A.interval&&g())};e.watch(()=>[A.interval,A.direction,A.items.length,A.pauseAutoplayOnHover],()=>{g()},{deep:!0});const C=()=>{A.pauseAutoplayOnHover&&(t.value=!0,p())},k=()=>{A.pauseAutoplayOnHover&&A.items.length>1&&(t.value=!1,g())};return e.onMounted(()=>{s.value="",requestAnimationFrame(()=>{requestAnimationFrame(()=>{s.value=d.value})}),A.interval&&A.items.length>1&&g()}),e.onBeforeUnmount(()=>{p()}),e.onScopeDispose(()=>{p()}),{clickNext:B,clickPrev:h,clickDot:w,pauseSlide:C,resumeSlide:k}}function _(A,i){const o=e.ref(new Map),r=e.ref(new Map),d=e.ref(new Set),s=t=>{o.value.set(t,!1),r.value.set(t,!1),d.value.add(t)},l=t=>{o.value.set(t,!1),r.value.set(t,!0)},u=t=>{if(!t||d.value.has(t))return;o.value.set(t,!0);const a=new Image;a.onload=()=>s(t),a.onerror=()=>l(t),a.src=t};return A&&i&&e.watch([A,i],()=>{const t=i.value[A.value],a=(A.value+1)%i.value.length,m=i.value[a];t!=null&&t.src&&u(t.src),m!=null&&m.src&&u(m.src)},{immediate:!0}),{loadingStates:o,errorStates:r,loadedImages:d,handleImageLoad:s,handleImageError:l,preloadImage:u}}const U=["aria-hidden"],$={class:"carousel-image-container",style:{width:"100%",height:"100%"}},G={key:0,class:"carousel-image-loading"},Z={key:1,class:"carousel-image-error"},Y=["src","alt","onLoad","onError"];return((A,i)=>{const o=A.__vccOpts||A;for(const[r,d]of i)o[r]=d;return o})(e.defineComponent({__name:"DirectionalCarousel",props:e.mergeModels({width:{default:"100%"},height:{default:"300px"},items:{},direction:{default:"right"},duration:{default:1e3},showPrev:{type:Boolean,default:!0},showNext:{type:Boolean,default:!0},showDots:{type:Boolean,default:!0},interval:{default:0},arrowOptions:{},pauseAutoplayOnHover:{type:Boolean,default:!1}},{currentIndex:{default:0},currentIndexModifiers:{}}),emits:["update:currentIndex"],setup(A,{expose:i}){const o=A,r=()=>{const n=E(o);if(n.length>0&&(n.forEach(c=>{console.error(`DirectionalCarousel: ${c.prop} - ${c.message}`)}),n.some(c=>c.prop==="items")))throw new Error("DirectionalCarousel: Invalid props - check console for details")};e.watch(()=>({items:o.items,interval:o.interval,duration:o.duration,width:o.width,height:o.height}),r,{immediate:!0});const d=e.ref(null),s=e.computed(()=>o.items.map(n=>typeof n=="string"?{src:n}:n)),l=e.computed(()=>o.items.length),u=e.computed(()=>[...s.value,s.value[0]]),t=e.useModel(A,"currentIndex"),a=e.ref(t.value),m=e.computed(()=>{var n;return((n=d.value)==null?void 0:n.offsetWidth)??0}),p=e.computed(()=>{var n;return((n=d.value)==null?void 0:n.offsetHeight)??0}),{itemsTranslate:g,defaultTransition:B,transition:v,isTransitioning:h,directionProps:w}=F(o,u,a,m,p),{clickNext:C,clickPrev:k,clickDot:b,pauseSlide:y,resumeSlide:Q}=j(o,s,u,a,B,v,h);e.watch(a,n=>{if(l.value===0)return;const c=n%l.value;t.value!==c&&(t.value=c)}),e.watch(t,n=>{if(typeof n!="number"||!Number.isInteger(n)||n<0||n>=l.value){console.warn(`DirectionalCarousel: invalid currentIndex "${n}". Must be an integer in [0, ${l.value-1}].`);const c=a.value%l.value;t.value!==c&&(t.value=c);return}h.value||a.value%l.value!==n&&(a.value=n)});const K=e.computed(()=>({overflow:"hidden",width:m.value+"px",height:p.value+"px",display:"flex",justifyContent:"center",alignItems:"center"})),{loadingStates:I,errorStates:V,loadedImages:N,preloadImage:re}=_(t,s),J=n=>{I.value.set(n,!1),N.value.add(n)},ee=n=>{I.value.set(n,!1),V.value.set(n,!0)};return i({currentIndex:t}),(n,c)=>{var z,X;return e.openBlock(),e.createElementBlock("div",{style:e.normalizeStyle({overflow:"hidden",display:"flex",flexDirection:"column",width:o.width,height:o.height})},[e.createElementVNode("div",{class:"slider",style:{overflow:"hidden",position:"relative",display:"flex",width:"100%",height:"100%"},onMouseenter:c[0]||(c[0]=(...f)=>e.unref(y)&&e.unref(y)(...f)),onFocusin:c[1]||(c[1]=(...f)=>e.unref(y)&&e.unref(y)(...f)),onMouseleave:c[2]||(c[2]=(...f)=>e.unref(Q)&&e.unref(Q)(...f)),onFocusout:c[3]||(c[3]=(...f)=>e.unref(Q)&&e.unref(Q)(...f))},[(z=n.arrowOptions)!=null&&z.prev.show||n.showPrev?(e.openBlock(),e.createBlock(L,{key:0,onClickPrevButton:e.unref(k)},null,8,["onClickPrevButton"])):e.createCommentVNode("",!0),e.createElementVNode("div",{ref_key:"carouselContainer",ref:d,style:{overflow:"hidden",position:"relative",flex:1}},[e.createElementVNode("div",{class:"wrapper-carousel-items",style:e.normalizeStyle({display:"inline-flex",position:"relative",flexDirection:e.unref(w).flexDirection,transform:e.unref(g),transition:e.unref(v),pointerEvents:e.unref(h)?"none":"auto"})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(u.value,(f,x)=>(e.openBlock(),e.createElementBlock("div",{key:x,style:e.normalizeStyle(K.value),class:"carousel-item","aria-hidden":a.value!==x},[e.renderSlot(n.$slots,"item",e.mergeProps({ref_for:!0},f,{style:{width:n.width,height:n.height}}),()=>[e.createElementVNode("div",$,[e.unref(I).get(f.src)?(e.openBlock(),e.createElementBlock("div",G,[e.renderSlot(n.$slots,"loading",{},()=>[c[4]||(c[4]=e.createElementVNode("div",{class:"loading-spinner"},null,-1))],!0)])):e.unref(V).get(f.src)?(e.openBlock(),e.createElementBlock("div",Z,[e.renderSlot(n.$slots,"error",{},()=>[c[5]||(c[5]=e.createElementVNode("div",{class:"error-fallback"},[e.createElementVNode("span",null,"Failed to load image")],-1))],!0)])):(e.openBlock(),e.createElementBlock("img",{key:2,src:f.src,alt:`Slide image ${x+1} of ${l.value}`,style:e.normalizeStyle({width:"100%",opacity:e.unref(N).has(f.src)?1:0,transition:"opacity 0.2s"}),onLoad:Ae=>J(f.src),onError:Ae=>ee(f.src)},null,44,Y))])],!0)],12,U))),128))],4)],512),(X=n.arrowOptions)!=null&&X.next.show||n.showNext?(e.openBlock(),e.createBlock(O,{key:1,onClickNextButton:e.unref(C)},null,8,["onClickNextButton"])):e.createCommentVNode("",!0)],32),n.showDots?(e.openBlock(),e.createBlock(R,{key:0,"current-index":t.value,"item-count":l.value,"show-dots":n.showDots,onClickDotButton:e.unref(b)},null,8,["current-index","item-count","show-dots","onClickDotButton"])):e.createCommentVNode("",!0)],4)}}}),[["__scopeId","data-v-4929f8ae"]])});