@neodrag/react
Version:
React library to add dragging to your apps 😉
1 lines • 5.76 kB
JavaScript
import{useRef as t,useState as e,useEffect as n}from"react";var r={dragStart:!0},o={delay:0,distance:3};function a(t,e={}){let n,a,{bounds:g,axis:h="both",gpuAcceleration:p=!0,legacyTranslate:m=!1,transform:y,applyUserSelectHack:w=!0,disabled:b=!1,ignoreMultitouch:D=!1,recomputeBounds:v=r,grid:E,threshold:S=o,position:x,cancel:A,handle:C,defaultClass:M="neodrag",defaultClassDragging:N="neodrag-dragging",defaultClassDragged:B="neodrag-dragged",defaultPosition:H={x:0,y:0},onDragStart:R,onDrag:T,onDragEnd:$}=e,L=!1,X=!1,Y=0,q=!1,P=!1,k=0,z=0,I=0,U=0,W=0,j=0,{x:F,y:G}=x?{x:x?.x??0,y:x?.y??0}:H;ot(F,G);let J,K,O,Q,V,Z="",_=!!x;v={...r,...v},S={...o,...S??{}};let tt=new Set;function et(t){L&&!X&&P&&q&&V&&(X=!0,function(t){at("neodrag:start",R,t)}(t),rt.add(N),w&&(Z=nt.userSelect,nt.userSelect="none"))}const nt=document.body.style,rt=t.classList;function ot(e=k,n=z){if(!y){if(m){let r=`${+e}px, ${+n}px`;return u(t,"transform",p?`translate3d(${r}, 0)`:`translate(${r})`)}return u(t,"translate",`${+e}px ${+n}px`)}const r=y({offsetX:e,offsetY:n,rootNode:t});d(r)&&u(t,"transform",r)}function at(e,n,r){const o=function(e){return{offsetX:k,offsetY:z,rootNode:t,currentNode:V,event:e}}(r);t.dispatchEvent(new CustomEvent(e,{detail:o})),n?.(o)}const it=addEventListener,dt=new AbortController,lt={signal:dt.signal,capture:!1};function st(){let e=t.offsetWidth/K.width;return isNaN(e)&&(e=1),e}return u(t,"touch-action","none"),it("pointerdown",(e=>{if(b)return;if(2===e.button)return;if(tt.add(e.pointerId),D&&tt.size>1)return e.preventDefault();if(v.dragStart&&(J=c(g,t)),d(C)&&d(A)&&C===A)throw new Error("`handle` selector can't be same as `cancel` selector");if(rt.add(M),O=function(t,e){if(!t)return[e];if(f(t))return[t];if(Array.isArray(t))return t;const n=e.querySelectorAll(t);if(null===n)throw new Error("Selector passed for `handle` option should be child of the element on which the action is applied");return Array.from(n.values())}(C,t),Q=function(t,e){if(!t)return[];if(f(t))return[t];if(Array.isArray(t))return t;const n=e.querySelectorAll(t);if(null===n)throw new Error("Selector passed for `cancel` option should be child of the element on which the action is applied");return Array.from(n.values())}(A,t),n=/(both|x)/.test(h),a=/(both|y)/.test(h),s(Q,O))throw new Error("Element being dragged can't be a child of the element on which `cancel` is applied");const r=e.composedPath()[0];if(!O.some((t=>t.contains(r)||t.shadowRoot?.contains(r)))||s(Q,[r]))return;V=1===O.length?t:O.find((t=>t.contains(r))),L=!0,Y=Date.now(),S.delay||(q=!0),K=t.getBoundingClientRect();const{clientX:o,clientY:i}=e,l=st();n&&(I=o-F/l),a&&(U=i-G/l),J&&(W=o-K.left,j=i-K.top)}),lt),it("pointermove",(e=>{if(!L||D&&tt.size>1)return;if(!X){if(!q){Date.now()-Y>=S.delay&&(q=!0,et(e))}if(!P){const t=e.clientX-I,n=e.clientY-U;Math.sqrt(t**2+n**2)>=S.distance&&(P=!0,et(e))}if(!X)return}v.drag&&(J=c(g,t)),e.preventDefault(),K=t.getBoundingClientRect();let r=e.clientX,o=e.clientY;const d=st();if(J){const t={left:J.left+W,top:J.top+j,right:J.right+W-K.width,bottom:J.bottom+j-K.height};r=i(r,t.left,t.right),o=i(o,t.top,t.bottom)}if(Array.isArray(E)){let[t,e]=E;if(isNaN(+t)||t<0)throw new Error("1st argument of `grid` must be a valid positive number");if(isNaN(+e)||e<0)throw new Error("2nd argument of `grid` must be a valid positive number");let n=r-I,a=o-U;[n,a]=l([t/d,e/d],n,a),r=I+n,o=U+a}n&&(k=Math.round((r-I)*d)),a&&(z=Math.round((o-U)*d)),F=k,G=z,at("neodrag",T,e),ot()}),lt),it("pointerup",(e=>{(tt.delete(e.pointerId),L)&&(X&&(it("click",(t=>t.stopPropagation()),{once:!0,signal:dt.signal,capture:!0}),v.dragEnd&&(J=c(g,t)),rt.remove(N),rt.add(B),w&&(nt.userSelect=Z),at("neodrag:end",$,e),n&&(I=k),a&&(U=z)),L=!1,X=!1,q=!1,P=!1)}),lt),{destroy:()=>dt.abort(),update:t=>{h=t.axis||"both",b=t.disabled??!1,D=t.ignoreMultitouch??!1,C=t.handle,g=t.bounds,v=t.recomputeBounds??r,A=t.cancel,w=t.applyUserSelectHack??!0,E=t.grid,p=t.gpuAcceleration??!0,m=t.legacyTranslate??!1,y=t.transform,S={...o,...t.threshold??{}};const e=rt.contains(B);rt.remove(M,B),M=t.defaultClass??"neodrag",N=t.defaultClassDragging??"neodrag-dragging",B=t.defaultClassDragged??"neodrag-dragged",rt.add(M),e&&rt.add(B),_&&(F=k=t.position?.x??k,G=z=t.position?.y??z,ot())}}}var i=(t,e,n)=>Math.min(Math.max(t,e),n),d=t=>"string"==typeof t,l=([t,e],n,r)=>{const o=(t,e)=>0===e?0:Math.ceil(t/e)*e;return[o(n,t),o(r,e)]};var s=(t,e)=>t.some((t=>e.some((e=>t.contains(e)))));function c(t,e){if(void 0===t)return;if(f(t))return t.getBoundingClientRect();if("object"==typeof t){const{top:e=0,left:n=0,right:r=0,bottom:o=0}=t;return{top:e,right:window.innerWidth-r,bottom:window.innerHeight-o,left:n}}if("parent"===t)return e.parentNode.getBoundingClientRect();const n=document.querySelector(t);if(null===n)throw new Error("The selector provided for bound doesn't exists in the document.");return n.getBoundingClientRect()}var u=(t,e,n)=>t.style.setProperty(e,n),f=t=>t instanceof HTMLElement;function g(t){return null==t||"string"==typeof t||t instanceof HTMLElement?t:"current"in t?t.current:Array.isArray(t)?t.map((t=>t instanceof HTMLElement?t:t.current)):void 0}function h(r,o={}){const i=t(),[d,l]=e(!1),[s,c]=e();let{onDragStart:u,onDrag:f,onDragEnd:h,handle:p,cancel:m}=o,y=g(p),w=g(m);function b(t,e){c(t),e?.(t)}function D(t){l(!0),b(t,u)}function v(t){b(t,f)}function E(t){l(!1),b(t,h)}return n((()=>{if("undefined"==typeof window)return;const t=r.current;if(!t)return;({onDragStart:u,onDrag:f,onDragEnd:h}=o);const{update:e,destroy:n}=a(t,{...o,handle:y,cancel:w,onDragStart:D,onDrag:v,onDragEnd:E});return i.current=e,n}),[]),n((()=>{i.current?.({...o,handle:g(p),cancel:g(m),onDragStart:D,onDrag:v,onDragEnd:E})}),[o]),{isDragging:d,dragState:s}}export{h as useDraggable};