splitpanes
Version:
A Vue.js reliable, simple and touch-ready panes splitter / resizer
2 lines (1 loc) • 10.1 kB
JavaScript
;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("vue"),te={__name:"splitpanes",props:{horizontal:{type:Boolean,default:!1},pushOtherPanes:{type:Boolean,default:!0},maximizePanes:{type:Boolean,default:!0},rtl:{type:Boolean,default:!1},firstSplitter:{type:Boolean,default:!1}},emits:["ready","resize","resized","pane-click","pane-maximize","pane-add","pane-remove","splitter-click","splitter-dblclick"],setup(b,{emit:h}){const M=h,c=b,w=s.useSlots(),o=s.ref([]),g=s.computed(()=>o.value.reduce((e,n)=>(e[~~n.id]=n)&&e,{})),m=s.computed(()=>o.value.length),x=s.ref(null),S=s.ref(!1),v=s.ref({mouseDown:!1,dragging:!1,activeSplitter:null,cursorOffset:0}),p=s.ref({splitter:null,timeoutId:null}),k=s.computed(()=>({[`splitpanes splitpanes--${c.horizontal?"horizontal":"vertical"}`]:!0,"splitpanes--dragging":v.value.dragging})),y=()=>{document.addEventListener("mousemove",u,{passive:!1}),document.addEventListener("mouseup",P),"ontouchstart"in window&&(document.addEventListener("touchmove",u,{passive:!1}),document.addEventListener("touchend",P))},N=()=>{document.removeEventListener("mousemove",u,{passive:!1}),document.removeEventListener("mouseup",P),"ontouchstart"in window&&(document.removeEventListener("touchmove",u,{passive:!1}),document.removeEventListener("touchend",P))},E=(e,n)=>{const i=e.target.closest(".splitpanes__splitter");if(i){const{left:t,top:a}=i.getBoundingClientRect(),{clientX:l,clientY:r}="ontouchstart"in window&&e.touches?e.touches[0]:e;v.value.cursorOffset=c.horizontal?r-a:l-t}y(),v.value.mouseDown=!0,v.value.activeSplitter=n},u=e=>{v.value.mouseDown&&(e.preventDefault(),v.value.dragging=!0,requestAnimationFrame(()=>{F(U(e)),f("resize",{event:e},!0)}))},P=e=>{v.value.dragging&&(window.getSelection().removeAllRanges(),f("resized",{event:e},!0)),v.value.mouseDown=!1,v.value.activeSplitter=null,setTimeout(()=>{v.value.dragging=!1,N()},100)},B=(e,n)=>{"ontouchstart"in window&&(e.preventDefault(),p.value.splitter===n?(clearTimeout(p.value.timeoutId),p.value.timeoutId=null,D(e,n),p.value.splitter=null):(p.value.splitter=n,p.value.timeoutId=setTimeout(()=>p.value.splitter=null,500))),v.value.dragging||f("splitter-click",{event:e,index:n},!0)},D=(e,n)=>{if(f("splitter-dblclick",{event:e,index:n},!0),c.maximizePanes){let i=0;o.value=o.value.map((t,a)=>(t.size=a===n?t.max:t.min,a!==n&&(i+=t.min),t)),o.value[n].size-=i,f("pane-maximize",{event:e,index:n,pane:o.value[n]}),f("resized",{event:e,index:n},!0)}},j=(e,n)=>{f("pane-click",{event:e,index:g.value[n].index,pane:g.value[n]})},U=e=>{const n=x.value.getBoundingClientRect(),{clientX:i,clientY:t}="ontouchstart"in window&&e.touches?e.touches[0]:e;return{x:i-(c.horizontal?0:v.value.cursorOffset)-n.left,y:t-(c.horizontal?v.value.cursorOffset:0)-n.top}},$=e=>{e=e[c.horizontal?"y":"x"];const n=x.value[c.horizontal?"clientHeight":"clientWidth"];return c.rtl&&!c.horizontal&&(e=n-e),e*100/n},F=e=>{const n=v.value.activeSplitter;let i={prevPanesSize:A(n),nextPanesSize:_(n),prevReachedMinPanes:0,nextReachedMinPanes:0};const t=0+(c.pushOtherPanes?0:i.prevPanesSize),a=100-(c.pushOtherPanes?0:i.nextPanesSize),l=Math.max(Math.min($(e),a),t);let r=[n,n+1],d=o.value[r[0]]||null,z=o.value[r[1]]||null;const L=d.max<100&&l>=d.max+i.prevPanesSize,ne=z.max<100&&l<=100-(z.max+_(n+1));if(L||ne){L?(d.size=d.max,z.size=Math.max(100-d.max-i.prevPanesSize-i.nextPanesSize,0)):(d.size=Math.max(100-z.max-i.prevPanesSize-_(n+1),0),z.size=z.max);return}if(c.pushOtherPanes){const T=H(i,l);if(!T)return;({sums:i,panesToResize:r}=T),d=o.value[r[0]]||null,z=o.value[r[1]]||null}d!==null&&(d.size=Math.min(Math.max(l-i.prevPanesSize-i.prevReachedMinPanes,d.min),d.max)),z!==null&&(z.size=Math.min(Math.max(100-l-i.nextPanesSize-i.nextReachedMinPanes,z.min),z.max))},H=(e,n)=>{const i=v.value.activeSplitter,t=[i,i+1];return n<e.prevPanesSize+o.value[t[0]].min&&(t[0]=G(i).index,e.prevReachedMinPanes=0,t[0]<i&&o.value.forEach((a,l)=>{l>t[0]&&l<=i&&(a.size=a.min,e.prevReachedMinPanes+=a.min)}),e.prevPanesSize=A(t[0]),t[0]===void 0)?(e.prevReachedMinPanes=0,o.value[0].size=o.value[0].min,o.value.forEach((a,l)=>{l>0&&l<=i&&(a.size=a.min,e.prevReachedMinPanes+=a.min)}),o.value[t[1]].size=100-e.prevReachedMinPanes-o.value[0].min-e.prevPanesSize-e.nextPanesSize,null):n>100-e.nextPanesSize-o.value[t[1]].min&&(t[1]=X(i).index,e.nextReachedMinPanes=0,t[1]>i+1&&o.value.forEach((a,l)=>{l>i&&l<t[1]&&(a.size=a.min,e.nextReachedMinPanes+=a.min)}),e.nextPanesSize=_(t[1]-1),t[1]===void 0)?(e.nextReachedMinPanes=0,o.value.forEach((a,l)=>{l<m.value-1&&l>=i+1&&(a.size=a.min,e.nextReachedMinPanes+=a.min)}),o.value[t[0]].size=100-e.prevPanesSize-_(t[0]-1),null):{sums:e,panesToResize:t}},A=e=>o.value.reduce((n,i,t)=>n+(t<e?i.size:0),0),_=e=>o.value.reduce((n,i,t)=>n+(t>e+1?i.size:0),0),G=e=>[...o.value].reverse().find(i=>i.index<e&&i.size>i.min)||{},X=e=>o.value.find(i=>i.index>e+1&&i.size>i.min)||{},Y=()=>{var n;const e=Array.from(((n=x.value)==null?void 0:n.children)||[]);for(const i of e){const t=i.classList.contains("splitpanes__pane"),a=i.classList.contains("splitpanes__splitter");!t&&!a&&(i.remove(),console.warn("Splitpanes: Only <pane> elements are allowed at the root of <splitpanes>. One of your DOM nodes was removed."))}},q=(e,n,i=!1)=>{const t=e-1,a=document.createElement("div");a.classList.add("splitpanes__splitter"),i||(a.onmousedown=l=>E(l,t),typeof window<"u"&&"ontouchstart"in window&&(a.ontouchstart=l=>E(l,t)),a.onclick=l=>B(l,t+1)),a.ondblclick=l=>D(l,t+1),n.parentNode.insertBefore(a,n)},W=e=>{e.onmousedown=void 0,e.onclick=void 0,e.ondblclick=void 0,e.remove()},R=()=>{var i;const e=Array.from(((i=x.value)==null?void 0:i.children)||[]);for(const t of e)t.className.includes("splitpanes__splitter")&&W(t);let n=0;for(const t of e)t.className.includes("splitpanes__pane")&&(!n&&c.firstSplitter?q(n,t,!0):n&&q(n,t),n++)},I=({uid:e,...n})=>{const i=g.value[e];for(const[t,a]of Object.entries(n))i[t]=a},J=e=>{var i;let n=-1;Array.from(((i=x.value)==null?void 0:i.children)||[]).some(t=>(t.className.includes("splitpanes__pane")&&n++,t.isSameNode(e.el))),o.value.splice(n,0,{...e,index:n}),o.value.forEach((t,a)=>t.index=a),S.value&&s.nextTick(()=>{R(),C({addedPane:o.value[n]}),f("pane-add",{pane:o.value[n]})})},K=e=>{const n=o.value.findIndex(t=>t.id===e);o.value[n].el=null;const i=o.value.splice(n,1)[0];o.value.forEach((t,a)=>t.index=a),s.nextTick(()=>{R(),f("pane-remove",{pane:i}),C({removedPane:{...i}})})},C=(e={})=>{!e.addedPane&&!e.removedPane?V():o.value.some(n=>n.givenSize!==null||n.min||n.max<100)?Z(e):Q(),S.value&&f("resized")},Q=()=>{const e=100/m.value;let n=0;const i=[],t=[];for(const a of o.value)a.size=Math.max(Math.min(e,a.max),a.min),n-=a.size,a.size>=a.max&&i.push(a.id),a.size<=a.min&&t.push(a.id);n>.1&&O(n,i,t)},V=()=>{let e=100;const n=[],i=[];let t=0;for(const l of o.value)e-=l.size,l.givenSize!==null&&t++,l.size>=l.max&&n.push(l.id),l.size<=l.min&&i.push(l.id);let a=100;if(e>.1){for(const l of o.value)l.givenSize===null&&(l.size=Math.max(Math.min(e/(m.value-t),l.max),l.min)),a-=l.size;a>.1&&O(a,n,i)}},Z=({addedPane:e,removedPane:n}={})=>{let i=100/m.value,t=0;const a=[],l=[];((e==null?void 0:e.givenSize)??null)!==null&&(i=(100-e.givenSize)/(m.value-1));for(const r of o.value)t-=r.size,r.size>=r.max&&a.push(r.id),r.size<=r.min&&l.push(r.id);if(!(Math.abs(t)<.1)){for(const r of o.value)(e==null?void 0:e.givenSize)!==null&&(e==null?void 0:e.id)===r.id||(r.size=Math.max(Math.min(i,r.max),r.min)),t-=r.size,r.size>=r.max&&a.push(r.id),r.size<=r.min&&l.push(r.id);t>.1&&O(t,a,l)}},O=(e,n,i)=>{let t;e>0?t=e/(m.value-n.length):t=e/(m.value-i.length),o.value.forEach((a,l)=>{if(e>0&&!n.includes(a.id)){const r=Math.max(Math.min(a.size+t,a.max),a.min),d=r-a.size;e-=d,a.size=r}else if(!i.includes(a.id)){const r=Math.max(Math.min(a.size+t,a.max),a.min),d=r-a.size;e-=d,a.size=r}}),Math.abs(e)>.1&&s.nextTick(()=>{S.value&&console.warn("Splitpanes: Could not resize panes correctly due to their constraints.")})},f=(e,n=void 0,i=!1)=>{const t=(n==null?void 0:n.index)??v.value.activeSplitter??null;M(e,{...n,...t!==null&&{index:t},...i&&t!==null&&{prevPane:o.value[t-(c.firstSplitter?1:0)],nextPane:o.value[t+(c.firstSplitter?0:1)]},panes:o.value.map(a=>({min:a.min,max:a.max,size:a.size}))})};s.watch(()=>c.firstSplitter,()=>R()),s.onMounted(()=>{Y(),R(),C(),f("ready"),S.value=!0}),s.onBeforeUnmount(()=>S.value=!1);const ee=()=>{var e;return s.h("div",{ref:x,class:k.value},(e=w.default)==null?void 0:e.call(w))};return s.provide("panes",o),s.provide("indexedPanes",g),s.provide("horizontal",s.computed(()=>c.horizontal)),s.provide("requestUpdate",I),s.provide("onPaneAdd",J),s.provide("onPaneRemove",K),s.provide("onPaneClick",j),(e,n)=>(s.openBlock(),s.createBlock(s.resolveDynamicComponent(ee)))}},ie={__name:"pane",props:{size:{type:[Number,String]},minSize:{type:[Number,String],default:0},maxSize:{type:[Number,String],default:100}},setup(b){var E;const h=b,M=s.inject("requestUpdate"),c=s.inject("onPaneAdd"),w=s.inject("horizontal"),o=s.inject("onPaneRemove"),g=s.inject("onPaneClick"),m=(E=s.getCurrentInstance())==null?void 0:E.uid,x=s.inject("indexedPanes"),S=s.computed(()=>x.value[m]),v=s.ref(null),p=s.computed(()=>{const u=isNaN(h.size)||h.size===void 0?0:parseFloat(h.size);return Math.max(Math.min(u,y.value),k.value)}),k=s.computed(()=>{const u=parseFloat(h.minSize);return isNaN(u)?0:u}),y=s.computed(()=>{const u=parseFloat(h.maxSize);return isNaN(u)?100:u}),N=s.computed(()=>{var u;return`${w.value?"height":"width"}: ${(u=S.value)==null?void 0:u.size}%`});return s.watch(()=>p.value,u=>M({uid:m,size:u})),s.watch(()=>k.value,u=>M({uid:m,min:u})),s.watch(()=>y.value,u=>M({uid:m,max:u})),s.onMounted(()=>{c({id:m,el:v.value,min:k.value,max:y.value,givenSize:h.size===void 0?null:p.value,size:p.value})}),s.onBeforeUnmount(()=>o(m)),(u,P)=>(s.openBlock(),s.createElementBlock("div",{ref_key:"paneEl",ref:v,class:"splitpanes__pane",onClick:P[0]||(P[0]=B=>s.unref(g)(B,u._.uid)),style:s.normalizeStyle(N.value)},[s.renderSlot(u.$slots,"default")],4))}};exports.Pane=ie;exports.Splitpanes=te;