UNPKG

react-split-pane

Version:

React split-pane component with hooks and TypeScript

3 lines (2 loc) 9.97 kB
"use strict";var e=require("react/jsx-runtime"),n=require("react");function t(...e){return e.filter(Boolean).join(" ")}const r=n.forwardRef(function(n,r){const{className:i,style:o,children:s,defaultSize:a,size:u,minSize:c,maxSize:l,...d}=n,p={position:"relative",outline:"none",overflow:"auto",flex:"none",...o},f=t("split-pane-pane",i);return e.jsx("div",{ref:r,className:f,style:p,"data-pane":"true",...d,children:s})});function i(e,n="polite"){if("undefined"==typeof document)return;const t=document.createElement("div");t.setAttribute("role","status"),t.setAttribute("aria-live",n),t.setAttribute("aria-atomic","true"),t.style.position="absolute",t.style.left="-10000px",t.style.width="1px",t.style.height="1px",t.style.overflow="hidden",t.textContent=e,document.body.appendChild(t),setTimeout(()=>{document.body.removeChild(t)},1e3)}function o(e){return 1e3>e?Math.round(e)+" pixels":Math.round(e/10)/100+" thousand pixels"}function s(n){const{direction:r,index:i,isDragging:o,disabled:s,onPointerDown:a,onKeyDown:u,className:c,style:l,currentSize:d,minSize:p,maxSize:f,children:m}=n,z="horizontal"===r?"vertical":"horizontal",h={...{flex:"none",position:"relative",userSelect:"none",touchAction:"none",..."horizontal"===r?{width:"1px",cursor:s?"default":"col-resize"}:{height:"1px",cursor:s?"default":"row-resize"},...o&&{cursor:"horizontal"===r?"col-resize":"row-resize"}},...l},v=t("split-pane-divider",r,o&&"dragging",c),y=function(e,n){return`${"horizontal"===n?"vertical":"horizontal"} divider ${e+1}`}(i,r),S=function(e){return`Use ${"horizontal"===e?"left and right arrow keys":"up and down arrow keys"} to resize. Hold Shift for larger steps. Press Home or End to minimize or maximize.`}(r);return e.jsx("div",{role:"separator","aria-orientation":z,"aria-label":y,"aria-valuenow":d,"aria-valuemin":p,"aria-valuemax":void 0===f||f===1/0?void 0:f,"aria-description":S,tabIndex:s?-1:0,className:v,style:h,onPointerDown:s?void 0:a,onKeyDown:s?void 0:u,"data-divider-index":i,children:m})}function a(e,n){if("number"==typeof e)return e;if(e.endsWith("%")){return parseFloat(e)/100*n}if(e.endsWith("px"))return parseFloat(e);const t=parseFloat(e);return isNaN(t)?0:t}function u(e,n,t){return Math.min(Math.max(e,n),t)}function c(e,n,t,r,i){const o=[...e],s=e[n]??0,a=e[n+1]??0,c=r[n+1]??0,l=i[n+1]??1/0;let d=u(s+t,r[n]??0,i[n]??1/0),p=u(a-t,c,l);const f=a-p,m=Math.min(Math.abs(d-s),Math.abs(f));return t>0?(d=s+m,p=a-m):(d=s-m,p=a+m),o[n]=d,o[n+1]=p,o}function l(e){const{direction:t,sizes:r,minSizes:i,maxSizes:o,snapPoints:s=[],snapTolerance:a=10,step:u,onResizeStart:l,onResize:d,onResizeEnd:p}=e,[f,m]=n.useState(!1),[z,h]=n.useState(r),v=n.useRef(null),y=n.useRef(null),S=n.useRef(!0),x=n.useRef(null),g=n.useRef(z);g.current=z;const w=n.useRef(p);w.current=p;const E=n.useRef(r);n.useEffect(()=>{f||JSON.stringify(r)===JSON.stringify(E.current)||(E.current=r,h(r))},[r,f]),n.useEffect(()=>(S.current=!0,()=>{S.current=!1,y.current&&(cancelAnimationFrame(y.current),y.current=null)}),[]);const b=n.useCallback((e,n)=>{if(!v.current||!S.current)return;const{dividerIndex:r,startPosition:l,startSizes:p,pointerType:f}=v.current;let m=("horizontal"===t?e:n)-l;u&&(m=function(e,n){return n>0?Math.round(e/n)*n:e}(m,u));let z=c(p,r,m,i,o);s.length>0&&(z=z.map(e=>function(e,n,t){for(const r of n)if(t>=Math.abs(e-r))return r;return e}(e,s,a))),h(z),d&&d(z,{sizes:z,source:"pointer",pointerType:f})},[t,u,i,o,s,a,d]),R=n.useCallback(e=>{v.current&&e.pointerId===v.current.pointerId&&(e.preventDefault(),x.current={x:e.clientX,y:e.clientY},y.current||(y.current=requestAnimationFrame(()=>{y.current=null,S.current&&x.current&&b(x.current.x,x.current.y)})))},[b]),k=n.useCallback(e=>{if(!v.current||e.pointerId!==v.current.pointerId)return;const{element:n,pointerId:t,pointerType:r}=v.current;n?.hasPointerCapture?.(t)&&n.releasePointerCapture(t),y.current&&(cancelAnimationFrame(y.current),y.current=null),m(!1);const i=g.current,o=w.current;o&&o(i,{sizes:i,source:"pointer",pointerType:r}),v.current=null},[]),P=n.useCallback(e=>n=>{n.preventDefault();const r="horizontal"===t?n.clientX:n.clientY,i=n.currentTarget;i.setPointerCapture(n.pointerId);const o=n.pointerType;v.current={dividerIndex:e,startPosition:r,startSizes:z,pointerId:n.pointerId,pointerType:o,element:i},m(!0),l&&l({sizes:z,source:"pointer",pointerType:o,originalEvent:n.nativeEvent})},[t,z,l]);return n.useEffect(()=>{if(f)return document.addEventListener("pointermove",R),document.addEventListener("pointerup",k),document.addEventListener("pointercancel",k),()=>{document.removeEventListener("pointermove",R),document.removeEventListener("pointerup",k),document.removeEventListener("pointercancel",k)}},[f,R,k]),{isDragging:f,currentSizes:z,handlePointerDown:P}}const d=10,p=50;function f(e){const{direction:t,sizes:r,minSizes:s,maxSizes:a,step:l=d,largeStep:f=p,onResize:m,onResizeEnd:z}=e,h=n.useRef(null);return{handleKeyDown:n.useCallback(e=>n=>{if(!("horizontal"===t?["ArrowLeft","ArrowRight"]:["ArrowUp","ArrowDown"]).includes(n.key)&&"Home"!==n.key&&"End"!==n.key&&"Escape"!==n.key)return;if(n.preventDefault(),"Escape"===n.key){if(h.current){const e=h.current;h.current=null,m&&m(e,{sizes:e,source:"keyboard",originalEvent:n.nativeEvent}),z&&z(e,{sizes:e,source:"keyboard",originalEvent:n.nativeEvent}),i("Pane sizes restored")}return}null===h.current&&(h.current=[...r]);let d=0,p=[...r],v="arrow";switch(n.key){case"ArrowLeft":case"ArrowUp":d=-(n.shiftKey?f:l);break;case"ArrowRight":case"ArrowDown":d=n.shiftKey?f:l;break;case"Home":{v="home";const n=e+1,t=s[e]??0,i=(r[e]??0)+(r[n]??0);p[e]=t,p[n]=i-t;break}case"End":{v="end";const n=e,t=e+1,i=(r[n]??0)+(r[t]??0);p[n]=Math.min(a[n]??1/0,i-(s[t]??0)),p[t]=i-p[n];break}}if(0!==d&&(p=c(r,e,d,s,a)),p=p.map((e,n)=>u(e,s[n]??0,a[n]??1/0)),m&&m(p,{sizes:p,source:"keyboard",originalEvent:n.nativeEvent}),z&&z(p,{sizes:p,source:"keyboard",originalEvent:n.nativeEvent}),"home"===v)i(`Pane ${e+1} minimized to ${o(p[e]??0)}`);else if("end"===v)i(`Pane ${e+1} maximized to ${o(p[e]??0)}`);else{const n=d>0?e:e+1;i(`Pane ${n+1} resized to ${o(p[n]??0)}`)}},[t,r,s,a,l,f,m,z])}}exports.Divider=s,exports.Pane=r,exports.SplitPane=function(i){const{direction:o="horizontal",resizable:u=!0,snapPoints:c,snapTolerance:d=10,step:p,onResizeStart:m,onResize:z,onResizeEnd:h,className:v,style:y,divider:S,dividerStyle:x,dividerClassName:g,dividerSize:w=1,children:E}=i,b=n.useRef(null),[R,k]=n.useState(0),P=n.useRef(0),D=n.useMemo(()=>n.Children.toArray(E).filter(e=>"object"==typeof e&&null!==e&&"props"in e).map(e=>({props:e.props,size:e.props.size,defaultSize:e.props.defaultSize,minSize:e.props.minSize??0,maxSize:e.props.maxSize??1/0})),[E]),A=D.length,C=n.useRef(!1);2>A&&!C.current&&(C.current=!0,console.warn(`SplitPane requires at least 2 Pane children. Received ${A}.`));const{minSizes:T,maxSizes:I}=n.useMemo(()=>{if(0===R)return{minSizes:Array(A).fill(0),maxSizes:Array(A).fill(1/0)};const e=[],n=[];return D.forEach(t=>{e.push(a(t.minSize,R)),n.push(t.maxSize===1/0?1/0:a(t.maxSize,R))}),{minSizes:e,maxSizes:n}},[R,A,D]),M=n.useCallback(e=>{if(0===e)return Array(A).fill(0);const n=e-w*(A-1),t=D.map(e=>{const t=e.size??e.defaultSize;return void 0!==t?a(t,n):null}),r=t.reduce((e,n)=>e+(n??0),0),i=t.filter(e=>null===e).length,o=i>0?(n-r)/i:0;return t.map(e=>null===e?o:e)},[A,D,w]),[N,$]=n.useState(()=>M(R));n.useEffect(()=>{if(0===R)return;if(!D.some(e=>void 0!==e.size))return;const e=M(R);$(n=>n.length===e.length&&n.every((n,t)=>n===e[t])?n:e)},[R,D,M]);const j=n.useCallback(e=>{const n=P.current;if(P.current=e,0===e)return;const t=D.some(e=>void 0!==e.size),r=e-w*(A-1);$(i=>i.every(e=>0===e)||i.length!==A?M(e):n>0&&n!==e?t?M(e):function(e,n){const t=e.reduce((e,n)=>e+n,0);if(0===t){const t=n/e.length;return e.map(()=>t)}return e.map(e=>e/t*n)}(i,r):0===n?M(e):i)},[A,D,M,w]),K=n.useRef(0);n.useEffect(()=>{const e=b.current;if(!e)return;const n=new ResizeObserver(e=>{const n=e[0];n&&(e=>{const n=Math.round("horizontal"===o?e.width:e.height);n>0&&n!==K.current&&(K.current=n,k(n),j(n))})(n.contentRect)});return n.observe(e),()=>{n.disconnect()}},[o,j]);const L=n.useCallback((e,n)=>{$(e),z?.(e,n)},[z]),{isDragging:F,currentSizes:O,handlePointerDown:q}=l({direction:o,sizes:N,minSizes:T,maxSizes:I,snapPoints:c,snapTolerance:d,step:p,onResizeStart:m,onResize:L,onResizeEnd:h}),{handleKeyDown:H}=f({direction:o,sizes:O,minSizes:T,maxSizes:I,step:p,onResize:L,onResizeEnd:h}),J=n.useCallback(e=>n=>{const t={...n,pointerId:1,pointerType:"mouse",nativeEvent:n.nativeEvent};q(e)(t)},[q]),X=n.useCallback(e=>n=>{const t=n.touches[0];if(!t)return;const r={...n,clientX:t.clientX,clientY:t.clientY,pointerId:t.identifier,pointerType:"touch",nativeEvent:n.nativeEvent};q(e)(r)},[q]),Y=n.useCallback(()=>{},[]),U={display:"flex",flexDirection:"horizontal"===o?"row":"column",height:"100%",width:"100%",overflow:"hidden",position:"relative",...y},W=t("split-pane",o,v);return e.jsx("div",{ref:b,className:W,style:U,children:R>0&&(()=>{if(2>A)return null;const n=[];return D.forEach((t,i)=>{const a=O[i]??0,c={..."horizontal"===o?{width:a+"px",height:"100%"}:{height:a+"px",width:"100%"},...t.props.style};if(n.push(e.jsx(r,{...t.props,style:c,children:t.props.children},"pane-"+i)),A-1>i){const t=T[i],r=I[i];n.push(e.jsx(S??s,{direction:o,index:i,isDragging:F,disabled:!u,onPointerDown:q(i),onMouseDown:J(i),onTouchStart:X(i),onTouchEnd:Y,onKeyDown:H(i),className:g,style:x,currentSize:a,minSize:t,maxSize:r===1/0?void 0:r},"divider-"+i))}}),n})()})},exports.useKeyboardResize=f,exports.usePersistence=function(e){const{key:t,storage:r=localStorage,debounce:i=300}=e,[o,s]=n.useState(()=>{try{const e=r.getItem(t);return e?JSON.parse(e):[]}catch{return[]}});return n.useEffect(()=>{if(0===o.length)return;const e=setTimeout(()=>{try{r.setItem(t,JSON.stringify(o))}catch(e){console.warn("Failed to persist pane sizes:",e)}},i);return()=>clearTimeout(e)},[o,t,r,i]),[o,s]},exports.useResizer=l; //# sourceMappingURL=index.cjs.map