react-native-reanimated-dnd 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import React,{createContext,useContext}from"react";import Animated from"react-native-reanimated";import{GestureDetector}from"react-native-gesture-handler";import{useDraggable}from"../hooks/useDraggable";const DraggableContext=createContext(null),Handle=({children:e,style:t})=>{const a=useContext(DraggableContext);return a?React.createElement(GestureDetector,{gesture:a.gesture},React.createElement(Animated.View,{style:t},e)):React.createElement(React.Fragment,null,e)},DraggableComponent=({style:e,children:t,...a})=>{const{animatedViewProps:r,gesture:n,state:l,hasHandle:o,animatedViewRef:c}=useDraggable({...a,children:t,handleComponent:Handle}),s={gesture:n,state:l},g=React.createElement(Animated.View,{ref:c,...r,style:[e,r.style],collapsable:!1},React.createElement(DraggableContext.Provider,{value:s},t));return o?g:React.createElement(GestureDetector,{gesture:n},g)};export const Draggable=Object.assign(DraggableComponent,{Handle});
1
+ import React,{createContext,useContext}from"react";import Animated from"react-native-reanimated";import{GestureDetector}from"react-native-gesture-handler";import{useDraggable}from"../hooks/useDraggable";const DraggableContext=createContext(null);const Handle=({children,style})=>{const draggableContext=useContext(DraggableContext);if(!draggableContext){console.warn("Draggable.Handle must be used within a Draggable component");return React.createElement(React.Fragment,null,children)}return React.createElement(GestureDetector,{gesture:draggableContext.gesture},React.createElement(Animated.View,{style},children))};const DraggableComponent=({style:componentStyle,children,...useDraggableHookOptions})=>{const{animatedViewProps,gesture,state,hasHandle,animatedViewRef}=useDraggable({...useDraggableHookOptions,children,handleComponent:Handle});const contextValue={gesture,state};const content=React.createElement(Animated.View,{ref:animatedViewRef,...animatedViewProps,style:[componentStyle,animatedViewProps.style],collapsable:false},React.createElement(DraggableContext.Provider,{value:contextValue},children));if(hasHandle){return content}else{return React.createElement(GestureDetector,{gesture},content)}};export const Draggable=Object.assign(DraggableComponent,{Handle});
@@ -1 +1 @@
1
- import React from"react";import Animated from"react-native-reanimated";import{useDroppable}from"../hooks/useDroppable";let _nextDroppableId=1;export const _getUniqueDroppableId=()=>_nextDroppableId++;export const Droppable=({onDrop:e,dropDisabled:t,onActiveChange:o,dropAlignment:p,dropOffset:r,activeStyle:a,droppableId:l,capacity:n,style:i,children:d})=>{const{viewProps:c,animatedViewRef:s}=useDroppable({onDrop:e,dropDisabled:t,onActiveChange:o,dropAlignment:p,dropOffset:r,activeStyle:a,droppableId:l,capacity:n});return React.createElement(Animated.View,{ref:s,...c,style:[i,c.style],collapsable:!1},d)};
1
+ import React from"react";import Animated from"react-native-reanimated";import{useDroppable}from"../hooks/useDroppable";let _nextDroppableId=1;export const _getUniqueDroppableId=()=>_nextDroppableId++;export const Droppable=({onDrop,dropDisabled,onActiveChange,dropAlignment,dropOffset,activeStyle,droppableId,capacity,style,children})=>{const{viewProps,animatedViewRef}=useDroppable({onDrop,dropDisabled,onActiveChange,dropAlignment,dropOffset,activeStyle,droppableId,capacity});return React.createElement(Animated.View,{ref:animatedViewRef,...viewProps,style:[style,viewProps.style],collapsable:false},children)};
@@ -1 +1 @@
1
- import React from"react";import{StyleSheet}from"react-native";import Animated from"react-native-reanimated";import{GestureHandlerRootView,ScrollView}from"react-native-gesture-handler";import{DropProvider}from"../context/DropContext";import{useSortableList}from"../hooks/useSortableList";const AnimatedScrollView=Animated.createAnimatedComponent(ScrollView);export function Sortable({data:e,renderItem:t,itemHeight:r,style:o,contentContainerStyle:l,itemKeyExtractor:n=e=>e.id}){const i={data:e,itemHeight:r,itemKeyExtractor:n},{scrollViewRef:a,dropProviderRef:c,handleScroll:m,handleScrollEnd:s,contentHeight:d,getItemProps:S}=useSortableList(i);return React.createElement(GestureHandlerRootView,{style:styles.flex},React.createElement(DropProvider,{ref:c},React.createElement(AnimatedScrollView,{ref:a,onScroll:m,scrollEventThrottle:16,style:[styles.scrollView,o],contentContainerStyle:[{height:d},l],onScrollEndDrag:s,onMomentumScrollEnd:s,simultaneousHandlers:c},e.map(((e,r)=>{const o={item:e,index:r,...S(e,r)};return t(o)})))))}const styles=StyleSheet.create({flex:{flex:1},scrollView:{flex:1,position:"relative",backgroundColor:"white"}});
1
+ import React from"react";import{StyleSheet}from"react-native";import Animated from"react-native-reanimated";import{GestureHandlerRootView,ScrollView}from"react-native-gesture-handler";import{DropProvider}from"../context/DropContext";import{useSortableList}from"../hooks/useSortableList";const AnimatedScrollView=Animated.createAnimatedComponent(ScrollView);export function Sortable({data,renderItem,itemHeight,style,contentContainerStyle,itemKeyExtractor=item=>item.id}){const sortableOptions={data,itemHeight,itemKeyExtractor};const{scrollViewRef,dropProviderRef,handleScroll,handleScrollEnd,contentHeight,getItemProps}=useSortableList(sortableOptions);return React.createElement(GestureHandlerRootView,{style:styles.flex},React.createElement(DropProvider,{ref:dropProviderRef},React.createElement(AnimatedScrollView,{ref:scrollViewRef,onScroll:handleScroll,scrollEventThrottle:16,style:[styles.scrollView,style],contentContainerStyle:[{height:contentHeight},contentContainerStyle],onScrollEndDrag:handleScrollEnd,onMomentumScrollEnd:handleScrollEnd,simultaneousHandlers:dropProviderRef},data.map(((item,index)=>{const itemProps=getItemProps(item,index);const sortableItemProps={item,index,...itemProps};return renderItem(sortableItemProps)})))))}const styles=StyleSheet.create({flex:{flex:1},scrollView:{flex:1,position:"relative",backgroundColor:"white"}});
@@ -1 +1 @@
1
- import React,{createContext,useContext}from"react";import Animated from"react-native-reanimated";import{PanGestureHandler}from"react-native-gesture-handler";import{useSortable}from"../hooks/useSortable";const SortableContext=createContext(null),SortableHandle=({children:e,style:t})=>{const n=useContext(SortableContext);return n?React.createElement(PanGestureHandler,{onGestureEvent:n.panGestureHandler},React.createElement(Animated.View,{style:t},e)):React.createElement(React.Fragment,null,e)};export function SortableItem({id:e,data:t,positions:n,lowerBound:a,autoScrollDirection:r,itemsCount:o,itemHeight:l,containerHeight:i,children:c,style:s,animatedStyle:d,onMove:m,onDragStart:u,onDrop:S,onDragging:g}){const H={id:e,positions:n,lowerBound:a,autoScrollDirection:r,itemsCount:o,itemHeight:l,containerHeight:i,onMove:m,onDragStart:u,onDrop:S,onDragging:g,children:c,handleComponent:SortableHandle},{animatedStyle:h,panGestureHandler:p,isMoving:b,hasHandle:C}=useSortable(H),v=[h,d],E={panGestureHandler:p},R=React.createElement(Animated.View,{style:v},React.createElement(SortableContext.Provider,{value:E},React.createElement(Animated.View,{style:s},c)));return C?R:React.createElement(PanGestureHandler,{onGestureEvent:p,activateAfterLongPress:200,shouldCancelWhenOutside:!1},R)}SortableItem.Handle=SortableHandle;
1
+ import React,{createContext,useContext}from"react";import Animated from"react-native-reanimated";import{PanGestureHandler}from"react-native-gesture-handler";import{useSortable}from"../hooks/useSortable";const SortableContext=createContext(null);const SortableHandle=({children,style})=>{const sortableContext=useContext(SortableContext);if(!sortableContext){console.warn("SortableHandle must be used within a SortableItem component");return React.createElement(React.Fragment,null,children)}return React.createElement(PanGestureHandler,{onGestureEvent:sortableContext.panGestureHandler},React.createElement(Animated.View,{style},children))};export function SortableItem({id,data,positions,lowerBound,autoScrollDirection,itemsCount,itemHeight,containerHeight,children,style,animatedStyle:customAnimatedStyle,onMove,onDragStart,onDrop,onDragging}){const sortableOptions={id,positions,lowerBound,autoScrollDirection,itemsCount,itemHeight,containerHeight,onMove,onDragStart,onDrop,onDragging,children,handleComponent:SortableHandle};const{animatedStyle,panGestureHandler,isMoving,hasHandle}=useSortable(sortableOptions);const combinedAnimatedStyle=[animatedStyle,customAnimatedStyle];const contextValue={panGestureHandler};const content=React.createElement(Animated.View,{style:combinedAnimatedStyle},React.createElement(SortableContext.Provider,{value:contextValue},React.createElement(Animated.View,{style},children)));if(hasHandle){return content}else{return React.createElement(PanGestureHandler,{onGestureEvent:panGestureHandler,activateAfterLongPress:200,shouldCancelWhenOutside:false},content)}}SortableItem.Handle=SortableHandle;
@@ -1 +1 @@
1
- export var ScrollDirection;!function(o){o.None="none",o.Up="up",o.Down="down"}(ScrollDirection||(ScrollDirection={}));export function clamp(o,t,n){return Math.max(t,Math.min(o,n))}export function objectMove(o,t,n){const e=Object.assign({},o);for(const c in o)o[c]===t&&(e[c]=n),o[c]===n&&(e[c]=t);return e}export function listToObject(o){const t=Object.values(o),n={};for(let o=0;o<t.length;o++)n[t[o].id]=o;return n}export function setPosition(o,t,n,e,c){const r=clamp(Math.floor(o/c),0,t-1);r!==n.value[e]&&(n.value=objectMove(n.value,n.value[e],r))}export function setAutoScroll(o,t,n,e,c){c.value=o<=t+e?ScrollDirection.Up:o>=n-e?ScrollDirection.Down:ScrollDirection.None}
1
+ export var ScrollDirection;(function(ScrollDirection){ScrollDirection["None"]="none";ScrollDirection["Up"]="up";ScrollDirection["Down"]="down"})(ScrollDirection||(ScrollDirection={}));export function clamp(value,lowerBound,upperBound){"worklet";return Math.max(lowerBound,Math.min(value,upperBound))}export function objectMove(object,from,to){"worklet";const newObject=Object.assign({},object);for(const id in object){if(object[id]===from){newObject[id]=to}if(object[id]===to){newObject[id]=from}}return newObject}export function listToObject(list){const values=Object.values(list);const object={};for(let i=0;i<values.length;i++){object[values[i].id]=i}return object}export function setPosition(positionY,itemsCount,positions,id,itemHeight){"worklet";const newPosition=clamp(Math.floor(positionY/itemHeight),0,itemsCount-1);if(newPosition!==positions.value[id]){positions.value=objectMove(positions.value,positions.value[id],newPosition)}}export function setAutoScroll(positionY,lowerBound,upperBound,scrollThreshold,autoScroll){"worklet";if(positionY<=lowerBound+scrollThreshold){autoScroll.value=ScrollDirection.Up}else if(positionY>=upperBound-scrollThreshold){autoScroll.value=ScrollDirection.Down}else{autoScroll.value=ScrollDirection.None}}
@@ -1 +1 @@
1
- import React,{useRef,useState,useMemo,useCallback,forwardRef,useImperativeHandle,useEffect}from"react";import{SlotsContext}from"../types/context";export const DropProvider=forwardRef((({children:e,onLayoutUpdateComplete:t,onDroppedItemsUpdate:r,onDragging:a,onDragStart:o,onDragEnd:s},n)=>{const l=useRef({}),[u,c]=useState(null),[i,d]=useState({}),p=useRef({}),g=useCallback(((e,t)=>{p.current[e]=t}),[]),v=useCallback((e=>{delete p.current[e]}),[]);useEffect((()=>{r&&r(i)}),[i,r]);const f=useCallback(((e,t,r)=>{d((a=>({...a,[e]:{droppableId:t,data:r}})))}),[]),m=useCallback((e=>{d((t=>{const r={...t};return delete r[e],r}))}),[]),b=useCallback((()=>i),[i]),D=useCallback((()=>{const e=p.current;Object.values(e).forEach((e=>{e()})),null==t||t()}),[t]);useImperativeHandle(n,(()=>({requestPositionUpdate:D,getDroppedItems:b})));const C=useCallback((e=>{const t=Object.values(i).filter((t=>t.droppableId===e)).length,r=Object.values(l.current).find((t=>t.id===e));return!!r&&t<(void 0!==r.capacity?r.capacity:1)}),[i]),I=useCallback((e=>{o&&o(e),D()}),[o,D]),S=useMemo((()=>({register:(e,t)=>{l.current[e]=t},unregister:e=>{delete l.current[e]},isRegistered:e=>void 0!==l.current[e],getSlots:()=>l.current,setActiveHoverSlot:e=>c(e),activeHoverSlotId:u,registerPositionUpdateListener:g,unregisterPositionUpdateListener:v,requestPositionUpdate:D,registerDroppedItem:f,unregisterDroppedItem:m,getDroppedItems:b,hasAvailableCapacity:C,onDragging:a,onDragStart:I,onDragEnd:s})),[u,g,v,D,f,m,b,C,a,I,s]);return React.createElement(SlotsContext.Provider,{value:S},e)}));DropProvider.displayName="DropProvider";
1
+ import React,{useRef,useState,useMemo,useCallback,forwardRef,useImperativeHandle,useEffect}from"react";import{SlotsContext}from"../types/context";export const DropProvider=forwardRef((({children,onLayoutUpdateComplete,onDroppedItemsUpdate,onDragging,onDragStart,onDragEnd},ref)=>{const slotsRef=useRef({});const[activeHoverSlotId,setActiveHoverSlotIdState]=useState(null);const[droppedItems,setDroppedItems]=useState({});const positionUpdateListenersRef=useRef({});const registerPositionUpdateListener=useCallback(((id,listener)=>{positionUpdateListenersRef.current[id]=listener}),[]);const unregisterPositionUpdateListener=useCallback((id=>{delete positionUpdateListenersRef.current[id]}),[]);useEffect((()=>{if(onDroppedItemsUpdate){onDroppedItemsUpdate(droppedItems)}}),[droppedItems,onDroppedItemsUpdate]);const registerDroppedItem=useCallback(((draggableId,droppableId,itemData)=>{setDroppedItems((prev=>({...prev,[draggableId]:{droppableId,data:itemData}})))}),[]);const unregisterDroppedItem=useCallback((draggableId=>{setDroppedItems((prev=>{const newItems={...prev};delete newItems[draggableId];return newItems}))}),[]);const getDroppedItems=useCallback((()=>droppedItems),[droppedItems]);const internalRequestPositionUpdate=useCallback((()=>{const listeners=positionUpdateListenersRef.current;Object.values(listeners).forEach((listener=>{listener()}));onLayoutUpdateComplete===null||onLayoutUpdateComplete===void 0?void 0:onLayoutUpdateComplete()}),[onLayoutUpdateComplete]);useImperativeHandle(ref,(()=>({requestPositionUpdate:internalRequestPositionUpdate,getDroppedItems})));const hasAvailableCapacity=useCallback((droppableId=>{const droppedCount=Object.values(droppedItems).filter((item=>item.droppableId===droppableId)).length;const droppableSlot=Object.values(slotsRef.current).find((slot=>slot.id===droppableId));if(!droppableSlot){return false}const capacity=droppableSlot.capacity!==undefined?droppableSlot.capacity:1;return droppedCount<capacity}),[droppedItems]);const handleDragStart=useCallback((data=>{if(onDragStart){onDragStart(data)}internalRequestPositionUpdate()}),[onDragStart,internalRequestPositionUpdate]);const contextValue=useMemo((()=>({register:(id,slot)=>{slotsRef.current[id]=slot},unregister:id=>{delete slotsRef.current[id]},isRegistered:id=>slotsRef.current[id]!==undefined,getSlots:()=>slotsRef.current,setActiveHoverSlot:id=>setActiveHoverSlotIdState(id),activeHoverSlotId,registerPositionUpdateListener,unregisterPositionUpdateListener,requestPositionUpdate:internalRequestPositionUpdate,registerDroppedItem,unregisterDroppedItem,getDroppedItems,hasAvailableCapacity,onDragging,onDragStart:handleDragStart,onDragEnd})),[activeHoverSlotId,registerPositionUpdateListener,unregisterPositionUpdateListener,internalRequestPositionUpdate,registerDroppedItem,unregisterDroppedItem,getDroppedItems,hasAvailableCapacity,onDragging,handleDragStart,onDragEnd]);return React.createElement(SlotsContext.Provider,{value:contextValue},children)}));DropProvider.displayName="DropProvider";
@@ -1 +1 @@
1
- import React,{useRef,useCallback,useContext,useEffect,useState}from"react";import{useSharedValue,useAnimatedStyle,withSpring,runOnJS,runOnUI,useAnimatedReaction,useAnimatedRef,measure}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";import{SlotsContext}from"../types/context";import{DraggableState}from"../types/draggable";export const useDraggable=e=>{const{data:a,draggableId:t,dragDisabled:u=!1,onDragStart:r,onDragEnd:n,onDragging:l,onStateChange:s,animationFunction:i,dragBoundsRef:o,dragAxis:v="both",collisionAlgorithm:c="intersect",children:h,handleComponent:d}=e,g=useAnimatedRef(),[S,f]=useState(DraggableState.IDLE),[m,p]=useState(!1);useEffect((()=>{if(!h||!d)return void p(!1);const e=a=>{if(React.isValidElement(a)){if(a.type===d)return!0;if(a.props&&a.props.children&&React.Children.toArray(a.props.children).some(e))return!0}return!1};p(React.Children.toArray(h).some(e))}),[h,d]),useEffect((()=>{null==s||s(S)}),[S,s]);const b=useSharedValue(0),y=useSharedValue(0),x=useSharedValue(0),D=useSharedValue(0),O=useSharedValue(u),V=useSharedValue(v),k=useSharedValue(0),C=useSharedValue(0),J=useSharedValue(0),w=useSharedValue(0),E=useRef(!1),R=useRef(t||`draggable-${Math.random().toString(36).substr(2,9)}`).current,I=useSharedValue(0),A=useSharedValue(0),U=useSharedValue(0),L=useSharedValue(0),M=useSharedValue(!1),{getSlots:P,setActiveHoverSlot:G,activeHoverSlotId:X,registerPositionUpdateListener:Y,unregisterPositionUpdateListener:H,registerDroppedItem:Z,unregisterDroppedItem:B,hasAvailableCapacity:F,onDragging:N,onDragStart:$,onDragEnd:j}=useContext(SlotsContext);useEffect((()=>{O.value=u}),[u,O]),useEffect((()=>{V.value=v}),[v,V]);const q=useCallback((()=>{runOnUI((()=>{const e=measure(g);if(null===e)return;const a=b.value,t=y.value;if(0===a&&0===t){const u=e.pageX-a,r=e.pageY-t;k.value=u,C.value=r}J.value=e.width,w.value=e.height,E.current||(E.current=!0)}))()}),[g,k,C,J,w,b,y]),z=useCallback((()=>{const e=measure(g);if(null===e)return;const a=b.value,t=y.value;if(0===a&&0===t){const u=e.pageX-a,r=e.pageY-t;k.value=u,C.value=r}J.value=e.width,w.value=e.height,E.current||(E.current=!0)}),[g,k,C,J,w,b,y]),K=useCallback((()=>{const e=null==o?void 0:o.current;e?e.measure(((e,a,t,u,r,n)=>{"number"==typeof r&&"number"==typeof n&&t>0&&u>0&&runOnUI((()=>{I.value=r,A.value=n,U.value=t,L.value=u,M.value||(M.value=!0)}))()})):runOnUI((()=>{M.value&&(M.value=!1)}))()}),[o,I,A,U,L,M]);useEffect((()=>(Y(R,(()=>{q(),K()})),()=>{H(R)})),[R,Y,H,q,K]),useEffect((()=>{K()}),[K]);const Q=useCallback((e=>{q()}),[q]),T=useCallback(((e,a)=>{i?(b.value=i(e),y.value=i(a)):(b.value=withSpring(e),y.value=withSpring(a))}),[i,b,y]),W=useCallback(((e,a,t,u,r,n)=>{if("intersect"===n)return e<r.x+r.width&&e+t>r.x&&a<r.y+r.height&&a+u>r.y;if("contain"===n)return e>=r.x&&e+t<=r.x+r.width&&a>=r.y&&a+u<=r.y+r.height;{const n=e+t/2,l=a+u/2;return n>=r.x&&n<=r.x+r.width&&l>=r.y&&l<=r.y+r.height}}),[]),_=useCallback(((e,a,t,u,r,n,l)=>{const s=P(),i=u+e,o=r+a;let v,h,d=null,g=null;for(const e in s){const a=parseInt(e,10),t=s[a];if(W(i,o,n,l,t,c)&&F(t.id)){d=t,g=a;break}}if(d&&null!==g){d.onDrop&&runOnJS(d.onDrop)(t),runOnJS(Z)(R,d.id,t),runOnJS(f)(DraggableState.DROPPED);const e=d.dropAlignment||"center",a=d.dropOffset||{x:0,y:0};let s=0,i=0;switch(e){case"top-left":s=d.x,i=d.y;break;case"top-center":s=d.x+d.width/2-n/2,i=d.y;break;case"top-right":s=d.x+d.width-n,i=d.y;break;case"center-left":s=d.x,i=d.y+d.height/2-l/2;break;case"center":default:s=d.x+d.width/2-n/2,i=d.y+d.height/2-l/2;break;case"center-right":s=d.x+d.width-n,i=d.y+d.height/2-l/2;break;case"bottom-left":s=d.x,i=d.y+d.height-l;break;case"bottom-center":s=d.x+d.width/2-n/2,i=d.y+d.height-l;break;case"bottom-right":s=d.x+d.width-n,i=d.y+d.height-l}v=s+a.x-u,h=i+a.y-r}else v=0,h=0,runOnJS(f)(DraggableState.IDLE),runOnJS(B)(R);runOnUI(T)(v,h)}),[P,T,c,W,f,R,Z,B,F]),ee=useCallback(((e,a,t,u,r,n)=>{const l=P(),s=t+e,i=u+a;let o=null;for(const e in l){const a=parseInt(e,10),t=l[a];if(W(s,i,r,n,t,c)){o=a;break}}X!==o&&G(o)}),[P,G,X,c,W]),ae=React.useMemo((()=>Gesture.Pan().onBegin((()=>{z(),O.value||(x.value=b.value,D.value=y.value,runOnJS(f)(DraggableState.DRAGGING),r&&runOnJS(r)(a),$&&runOnJS($)(a))})).onUpdate((e=>{if(O.value)return;let t=x.value+e.translationX,u=D.value+e.translationY;if(M.value){const e=J.value,a=w.value,r=I.value-k.value,n=I.value+U.value-k.value-e,l=A.value-C.value,s=A.value+L.value-C.value-a;t=Math.max(r,Math.min(t,n)),u=Math.max(l,Math.min(u,s))}"x"===V.value?b.value=t:("y"===V.value||(b.value=t),y.value=u),l&&runOnJS(l)({x:k.value,y:C.value,tx:b.value,ty:y.value,itemData:a}),N&&runOnJS(N)({x:k.value,y:C.value,tx:b.value,ty:y.value,itemData:a}),runOnJS(ee)(b.value,y.value,k.value,C.value,J.value,w.value)})).onEnd((()=>{O.value||(n&&runOnJS(n)(a),j&&runOnJS(j)(a),runOnJS(_)(b.value,y.value,a,k.value,C.value,J.value,w.value),runOnJS(G)(null))}))),[O,x,D,b,y,k,C,J,w,r,n,a,_,ee,G,i,l,M,I,A,U,L,V,f,z,N,$,j]),te=useAnimatedStyle((()=>({transform:[{translateX:b.value},{translateY:y.value}]})),[b,y]);return useAnimatedReaction((()=>({txValue:b.value,tyValue:y.value,isZero:0===b.value&&0===y.value})),((e,a)=>{e.isZero&&a&&!a.isZero&&(runOnJS(f)(DraggableState.IDLE),runOnJS(B)(R))}),[f,B,R]),useEffect((()=>()=>{B(R)}),[R,B]),{animatedViewProps:{style:te,onLayout:Q},gesture:ae,state:S,animatedViewRef:g,hasHandle:m}};
1
+ import React,{useRef,useCallback,useContext,useEffect,useState}from"react";import{useSharedValue,useAnimatedStyle,withSpring,runOnJS,runOnUI,useAnimatedReaction,useAnimatedRef,measure}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";import{SlotsContext}from"../types/context";import{DraggableState}from"../types/draggable";export const useDraggable=options=>{const{data,draggableId,dragDisabled=false,onDragStart,onDragEnd,onDragging,onStateChange,animationFunction,dragBoundsRef,dragAxis="both",collisionAlgorithm="intersect",children,handleComponent}=options;const animatedViewRef=useAnimatedRef();const[state,setState]=useState(DraggableState.IDLE);const[hasHandle,setHasHandle]=useState(false);useEffect((()=>{if(!children||!handleComponent){setHasHandle(false);return}const checkForHandle=child=>{if(React.isValidElement(child)){if(child.type===handleComponent){return true}if(child.props&&child.props.children){if(React.Children.toArray(child.props.children).some(checkForHandle)){return true}}}return false};setHasHandle(React.Children.toArray(children).some(checkForHandle))}),[children,handleComponent]);useEffect((()=>{onStateChange===null||onStateChange===void 0?void 0:onStateChange(state)}),[state,onStateChange]);const tx=useSharedValue(0);const ty=useSharedValue(0);const offsetX=useSharedValue(0);const offsetY=useSharedValue(0);const dragDisabledShared=useSharedValue(dragDisabled);const dragAxisShared=useSharedValue(dragAxis);const originX=useSharedValue(0);const originY=useSharedValue(0);const itemW=useSharedValue(0);const itemH=useSharedValue(0);const isOriginSet=useRef(false);const internalDraggableId=useRef(draggableId||`draggable-${Math.random().toString(36).substr(2,9)}`).current;const boundsX=useSharedValue(0);const boundsY=useSharedValue(0);const boundsWidth=useSharedValue(0);const boundsHeight=useSharedValue(0);const boundsAreSet=useSharedValue(false);const{getSlots,setActiveHoverSlot,activeHoverSlotId,registerPositionUpdateListener,unregisterPositionUpdateListener,registerDroppedItem,unregisterDroppedItem,hasAvailableCapacity,onDragging:contextOnDragging,onDragStart:contextOnDragStart,onDragEnd:contextOnDragEnd}=useContext(SlotsContext);useEffect((()=>{dragDisabledShared.value=dragDisabled}),[dragDisabled,dragDisabledShared]);useEffect((()=>{dragAxisShared.value=dragAxis}),[dragAxis,dragAxisShared]);const updateDraggablePosition=useCallback((()=>{runOnUI((()=>{"worklet";const measurement=measure(animatedViewRef);if(measurement===null){return}const currentTx=tx.value;const currentTy=ty.value;if(currentTx===0&&currentTy===0){const newOriginX=measurement.pageX-currentTx;const newOriginY=measurement.pageY-currentTy;originX.value=newOriginX;originY.value=newOriginY}itemW.value=measurement.width;itemH.value=measurement.height;if(!isOriginSet.current){isOriginSet.current=true}}))()}),[animatedViewRef,originX,originY,itemW,itemH,tx,ty]);const updateDraggablePositionWorklet=useCallback((()=>{"worklet";const measurement=measure(animatedViewRef);if(measurement===null){return}const currentTx=tx.value;const currentTy=ty.value;if(currentTx===0&&currentTy===0){const newOriginX=measurement.pageX-currentTx;const newOriginY=measurement.pageY-currentTy;originX.value=newOriginX;originY.value=newOriginY}itemW.value=measurement.width;itemH.value=measurement.height;if(!isOriginSet.current){isOriginSet.current=true}}),[animatedViewRef,originX,originY,itemW,itemH,tx,ty]);const updateBounds=useCallback((()=>{const currentBoundsView=dragBoundsRef===null||dragBoundsRef===void 0?void 0:dragBoundsRef.current;if(currentBoundsView){currentBoundsView.measure(((_x,_y,width,height,pageX,pageY)=>{if(typeof pageX==="number"&&typeof pageY==="number"&&width>0&&height>0){runOnUI((()=>{"worklet";boundsX.value=pageX;boundsY.value=pageY;boundsWidth.value=width;boundsHeight.value=height;if(!boundsAreSet.value){boundsAreSet.value=true}}))()}else{console.warn("useDraggable: dragBoundsRef measurement failed or returned invalid dimensions. Bounds may be stale or item unbounded.")}}))}else{runOnUI((()=>{"worklet";if(boundsAreSet.value){boundsAreSet.value=false}}))()}}),[dragBoundsRef,boundsX,boundsY,boundsWidth,boundsHeight,boundsAreSet]);useEffect((()=>{const handlePositionUpdate=()=>{updateDraggablePosition();updateBounds()};registerPositionUpdateListener(internalDraggableId,handlePositionUpdate);return()=>{unregisterPositionUpdateListener(internalDraggableId)}}),[internalDraggableId,registerPositionUpdateListener,unregisterPositionUpdateListener,updateDraggablePosition,updateBounds]);useEffect((()=>{updateBounds()}),[updateBounds]);const handleLayoutHandler=useCallback((event=>{updateDraggablePosition()}),[updateDraggablePosition]);const animateDragEndPosition=useCallback(((targetXValue,targetYValue)=>{"worklet";if(animationFunction){tx.value=animationFunction(targetXValue);ty.value=animationFunction(targetYValue)}else{tx.value=withSpring(targetXValue);ty.value=withSpring(targetYValue)}}),[animationFunction,tx,ty]);const performCollisionCheck=useCallback(((draggableX,draggableY,draggableW,draggableH,slot,algo)=>{if(algo==="intersect"){return draggableX<slot.x+slot.width&&draggableX+draggableW>slot.x&&draggableY<slot.y+slot.height&&draggableY+draggableH>slot.y}else if(algo==="contain"){return draggableX>=slot.x&&draggableX+draggableW<=slot.x+slot.width&&draggableY>=slot.y&&draggableY+draggableH<=slot.y+slot.height}else{const draggableCenterX=draggableX+draggableW/2;const draggableCenterY=draggableY+draggableH/2;return draggableCenterX>=slot.x&&draggableCenterX<=slot.x+slot.width&&draggableCenterY>=slot.y&&draggableCenterY<=slot.y+slot.height}}),[]);const processDropAndAnimate=useCallback(((currentTxVal,currentTyVal,draggableData,currentOriginX,currentOriginY,currentItemW,currentItemH)=>{const slots=getSlots();const currentDraggableX=currentOriginX+currentTxVal;const currentDraggableY=currentOriginY+currentTyVal;let hitSlotData=null;let hitSlotId=null;for(const key in slots){const slotId=parseInt(key,10);const s=slots[slotId];const isCollision=performCollisionCheck(currentDraggableX,currentDraggableY,currentItemW,currentItemH,s,collisionAlgorithm);if(isCollision){const hasCapacity=hasAvailableCapacity(s.id);if(hasCapacity){hitSlotData=s;hitSlotId=slotId;break}}}let finalTxValue;let finalTyValue;if(hitSlotData&&hitSlotId!==null){if(hitSlotData.onDrop){runOnJS(hitSlotData.onDrop)(draggableData)}runOnJS(registerDroppedItem)(internalDraggableId,hitSlotData.id,draggableData);runOnJS(setState)(DraggableState.DROPPED);const alignment=hitSlotData.dropAlignment||"center";const offset=hitSlotData.dropOffset||{x:0,y:0};let targetX=0;let targetY=0;switch(alignment){case"top-left":targetX=hitSlotData.x;targetY=hitSlotData.y;break;case"top-center":targetX=hitSlotData.x+hitSlotData.width/2-currentItemW/2;targetY=hitSlotData.y;break;case"top-right":targetX=hitSlotData.x+hitSlotData.width-currentItemW;targetY=hitSlotData.y;break;case"center-left":targetX=hitSlotData.x;targetY=hitSlotData.y+hitSlotData.height/2-currentItemH/2;break;case"center":targetX=hitSlotData.x+hitSlotData.width/2-currentItemW/2;targetY=hitSlotData.y+hitSlotData.height/2-currentItemH/2;break;case"center-right":targetX=hitSlotData.x+hitSlotData.width-currentItemW;targetY=hitSlotData.y+hitSlotData.height/2-currentItemH/2;break;case"bottom-left":targetX=hitSlotData.x;targetY=hitSlotData.y+hitSlotData.height-currentItemH;break;case"bottom-center":targetX=hitSlotData.x+hitSlotData.width/2-currentItemW/2;targetY=hitSlotData.y+hitSlotData.height-currentItemH;break;case"bottom-right":targetX=hitSlotData.x+hitSlotData.width-currentItemW;targetY=hitSlotData.y+hitSlotData.height-currentItemH;break;default:targetX=hitSlotData.x+hitSlotData.width/2-currentItemW/2;targetY=hitSlotData.y+hitSlotData.height/2-currentItemH/2}const draggableTargetX=targetX+offset.x;const draggableTargetY=targetY+offset.y;finalTxValue=draggableTargetX-currentOriginX;finalTyValue=draggableTargetY-currentOriginY}else{finalTxValue=0;finalTyValue=0;runOnJS(setState)(DraggableState.IDLE);runOnJS(unregisterDroppedItem)(internalDraggableId)}runOnUI(animateDragEndPosition)(finalTxValue,finalTyValue)}),[getSlots,animateDragEndPosition,collisionAlgorithm,performCollisionCheck,setState,internalDraggableId,registerDroppedItem,unregisterDroppedItem,hasAvailableCapacity]);const updateHoverState=useCallback(((currentTxVal,currentTyVal,currentOriginX,currentOriginY,currentItemW,currentItemH)=>{const slots=getSlots();const currentDraggableX=currentOriginX+currentTxVal;const currentDraggableY=currentOriginY+currentTyVal;let newHoveredSlotId=null;for(const key in slots){const slotId=parseInt(key,10);const s=slots[slotId];const isCollision=performCollisionCheck(currentDraggableX,currentDraggableY,currentItemW,currentItemH,s,collisionAlgorithm);if(isCollision){newHoveredSlotId=slotId;break}}if(activeHoverSlotId!==newHoveredSlotId){setActiveHoverSlot(newHoveredSlotId)}}),[getSlots,setActiveHoverSlot,activeHoverSlotId,collisionAlgorithm,performCollisionCheck]);const gesture=React.useMemo((()=>Gesture.Pan().onBegin((()=>{"worklet";updateDraggablePositionWorklet();if(dragDisabledShared.value){return}offsetX.value=tx.value;offsetY.value=ty.value;runOnJS(setState)(DraggableState.DRAGGING);if(onDragStart){runOnJS(onDragStart)(data)}if(contextOnDragStart){runOnJS(contextOnDragStart)(data)}})).onUpdate((event=>{"worklet";if(dragDisabledShared.value){return}let newTx=offsetX.value+event.translationX;let newTy=offsetY.value+event.translationY;if(boundsAreSet.value){const currentItemW=itemW.value;const currentItemH=itemH.value;const minTx=boundsX.value-originX.value;const maxTx=boundsX.value+boundsWidth.value-originX.value-currentItemW;const minTy=boundsY.value-originY.value;const maxTy=boundsY.value+boundsHeight.value-originY.value-currentItemH;newTx=Math.max(minTx,Math.min(newTx,maxTx));newTy=Math.max(minTy,Math.min(newTy,maxTy))}if(dragAxisShared.value==="x"){tx.value=newTx}else if(dragAxisShared.value==="y"){ty.value=newTy}else{tx.value=newTx;ty.value=newTy}if(onDragging){runOnJS(onDragging)({x:originX.value,y:originY.value,tx:tx.value,ty:ty.value,itemData:data})}if(contextOnDragging){runOnJS(contextOnDragging)({x:originX.value,y:originY.value,tx:tx.value,ty:ty.value,itemData:data})}runOnJS(updateHoverState)(tx.value,ty.value,originX.value,originY.value,itemW.value,itemH.value)})).onEnd((()=>{"worklet";if(dragDisabledShared.value){return}if(onDragEnd){runOnJS(onDragEnd)(data)}if(contextOnDragEnd){runOnJS(contextOnDragEnd)(data)}runOnJS(processDropAndAnimate)(tx.value,ty.value,data,originX.value,originY.value,itemW.value,itemH.value);runOnJS(setActiveHoverSlot)(null)}))),[dragDisabledShared,offsetX,offsetY,tx,ty,originX,originY,itemW,itemH,onDragStart,onDragEnd,data,processDropAndAnimate,updateHoverState,setActiveHoverSlot,animationFunction,onDragging,boundsAreSet,boundsX,boundsY,boundsWidth,boundsHeight,dragAxisShared,setState,updateDraggablePositionWorklet,contextOnDragging,contextOnDragStart,contextOnDragEnd]);const animatedStyleProp=useAnimatedStyle((()=>{"worklet";return{transform:[{translateX:tx.value},{translateY:ty.value}]}}),[tx,ty]);useAnimatedReaction((()=>({txValue:tx.value,tyValue:ty.value,isZero:tx.value===0&&ty.value===0})),((result,previous)=>{if(result.isZero&&previous&&!previous.isZero){runOnJS(setState)(DraggableState.IDLE);runOnJS(unregisterDroppedItem)(internalDraggableId)}}),[setState,unregisterDroppedItem,internalDraggableId]);useEffect((()=>()=>{unregisterDroppedItem(internalDraggableId)}),[internalDraggableId,unregisterDroppedItem]);return{animatedViewProps:{style:animatedStyleProp,onLayout:handleLayoutHandler},gesture,state,animatedViewRef,hasHandle}};
@@ -1 +1 @@
1
- import{useRef,useEffect,useContext,useCallback,useMemo}from"react";import{StyleSheet}from"react-native";import{useAnimatedRef,measure,runOnUI,runOnJS}from"react-native-reanimated";import{SlotsContext}from"../types/context";import{_getUniqueDroppableId}from"../components/Droppable";export const useDroppable=e=>{const{onDrop:t,dropDisabled:r,onActiveChange:o,dropAlignment:s,dropOffset:n,activeStyle:a,droppableId:i,capacity:u}=e,c=useAnimatedRef(),p=useRef(_getUniqueDroppableId()).current,f=useRef(i||`droppable-${p}`).current,l=useRef(`droppable-${p}-${Math.random().toString(36).substr(2,9)}`).current,{register:m,unregister:d,isRegistered:g,activeHoverSlotId:y,registerPositionUpdateListener:v,unregisterPositionUpdateListener:S}=useContext(SlotsContext),h=y===p,{processedActiveStyle:b,activeTransforms:A}=useMemo((()=>{if(!h||!a)return{processedActiveStyle:null,activeTransforms:[]};const e=StyleSheet.flatten(a);let t={...e},r=[];return e.transform&&(Array.isArray(e.transform)&&(r=[...e.transform]),delete t.transform),{processedActiveStyle:t,activeTransforms:r}}),[h,a]),x=useMemo((()=>{if(h&&a)return 0===A.length?b:{...b,transform:A}}),[h,a,b,A]);useEffect((()=>{null==o||o(h)}),[h,o]),useEffect((()=>{}),[p,f,i]);const C=useCallback((()=>{runOnUI((()=>{const e=measure(c);null!==e&&e.width>0&&e.height>0&&runOnJS(m)(p,{id:i||`droppable-${p}`,x:e.pageX,y:e.pageY,width:e.width,height:e.height,onDrop:t,dropAlignment:s||"center",dropOffset:n||{x:0,y:0},capacity:u})}))()}),[p,i,t,m,c,s,n,u]),R=useCallback((e=>{C()}),[C]);return useEffect((()=>(v(l,C),()=>{S(l)})),[l,v,S,C]),useEffect((()=>{r?d(p):C()}),[r,p,d,C]),useEffect((()=>()=>{d(p)}),[p,d]),{viewProps:{onLayout:R,style:x},isActive:h,activeStyle:a,animatedViewRef:c}};
1
+ import{useRef,useEffect,useContext,useCallback,useMemo}from"react";import{StyleSheet}from"react-native";import{useAnimatedRef,measure,runOnUI,runOnJS}from"react-native-reanimated";import{SlotsContext}from"../types/context";import{_getUniqueDroppableId}from"../components/Droppable";export const useDroppable=options=>{const{onDrop,dropDisabled,onActiveChange,dropAlignment,dropOffset,activeStyle,droppableId,capacity}=options;const animatedViewRef=useAnimatedRef();const id=useRef(_getUniqueDroppableId()).current;const stringId=useRef(droppableId||`droppable-${id}`).current;const instanceId=useRef(`droppable-${id}-${Math.random().toString(36).substr(2,9)}`).current;const{register,unregister,isRegistered,activeHoverSlotId:contextActiveHoverSlotId,registerPositionUpdateListener,unregisterPositionUpdateListener}=useContext(SlotsContext);const isActive=contextActiveHoverSlotId===id;const{processedActiveStyle,activeTransforms}=useMemo((()=>{if(!isActive||!activeStyle){return{processedActiveStyle:null,activeTransforms:[]}}const flattenedStyle=StyleSheet.flatten(activeStyle);let processedStyle={...flattenedStyle};let transforms=[];if(flattenedStyle.transform){if(Array.isArray(flattenedStyle.transform)){transforms=[...flattenedStyle.transform]}delete processedStyle.transform}return{processedActiveStyle:processedStyle,activeTransforms:transforms}}),[isActive,activeStyle]);const combinedActiveStyle=useMemo((()=>{if(!isActive||!activeStyle){return undefined}if(activeTransforms.length===0){return processedActiveStyle}return{...processedActiveStyle,transform:activeTransforms}}),[isActive,activeStyle,processedActiveStyle,activeTransforms]);useEffect((()=>{onActiveChange===null||onActiveChange===void 0?void 0:onActiveChange(isActive)}),[isActive,onActiveChange]);useEffect((()=>{console.log(`Droppable ${id} using string ID: ${stringId}, provided ID: ${droppableId||"none"}`)}),[id,stringId,droppableId]);const updateDroppablePosition=useCallback((()=>{runOnUI((()=>{"worklet";const measurement=measure(animatedViewRef);if(measurement===null){return}if(measurement.width>0&&measurement.height>0){runOnJS(register)(id,{id:droppableId||`droppable-${id}`,x:measurement.pageX,y:measurement.pageY,width:measurement.width,height:measurement.height,onDrop,dropAlignment:dropAlignment||"center",dropOffset:dropOffset||{x:0,y:0},capacity})}}))()}),[id,droppableId,onDrop,register,animatedViewRef,dropAlignment,dropOffset,capacity]);const handleLayoutHandler=useCallback((_event=>{updateDroppablePosition()}),[updateDroppablePosition]);useEffect((()=>{registerPositionUpdateListener(instanceId,updateDroppablePosition);return()=>{unregisterPositionUpdateListener(instanceId)}}),[instanceId,registerPositionUpdateListener,unregisterPositionUpdateListener,updateDroppablePosition]);useEffect((()=>{if(dropDisabled){unregister(id)}else{updateDroppablePosition()}}),[dropDisabled,id,unregister,updateDroppablePosition]);useEffect((()=>()=>{unregister(id)}),[id,unregister]);return{viewProps:{onLayout:handleLayoutHandler,style:combinedActiveStyle},isActive,activeStyle,animatedViewRef}};
@@ -1 +1 @@
1
- import{useState,useRef,useEffect}from"react";import React from"react";import{runOnJS,runOnUI,useAnimatedGestureHandler,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";export var ScrollDirection;!function(e){e.None="none",e.Up="up",e.Down="down"}(ScrollDirection||(ScrollDirection={}));export function clamp(e,t,n){return Math.max(t,Math.min(e,n))}export function objectMove(e,t,n){const a=Object.assign({},e);for(const l in e)e[l]===t&&(a[l]=n),e[l]===n&&(a[l]=t);return a}export function listToObject(e){const t=Object.values(e),n={};for(let e=0;e<t.length;e++)n[t[e].id]=e;return n}export function setPosition(e,t,n,a,l){const u=clamp(Math.floor(e/l),0,t-1);u!==n.value[a]&&(n.value=objectMove(n.value,n.value[a],u))}export function setAutoScroll(e,t,n,a,l){l.value=e<=t+a?ScrollDirection.Up:e>=n-a?ScrollDirection.Down:ScrollDirection.None}export function useSortable(e){const{id:t,positions:n,lowerBound:a,autoScrollDirection:l,itemsCount:u,itemHeight:o,containerHeight:i=500,onMove:r,onDragStart:s,onDrop:c,onDragging:v,children:d,handleComponent:S}=e,[h,m]=useState(!1),[f,p]=useState(!1),g=useSharedValue(!1),w=useSharedValue(null),D=useSharedValue(0),b=useSharedValue(0),A=useSharedValue(0),O=useSharedValue(0);useEffect((()=>{runOnUI((()=>{const e=n.value[t]*o,l=a.value;A.value=e,b.value=e,O.value=l}))()}),[]);const R=useRef(i).current,M=useDerivedValue((()=>a.value+R));useEffect((()=>{if(!d||!S)return void p(!1);const e=t=>{if(React.isValidElement(t)){if(t.type===S)return!0;if(t.props&&t.props.children&&React.Children.toArray(t.props.children).some(e))return!0}return!1};p(React.Children.toArray(d).some(e))}),[d,S]),useAnimatedReaction((()=>b.value),((e,i)=>{if(null===e||!g.value)return;if(null!==i&&e===i)return;const r=Math.min(Math.max(0,Math.ceil(e/o)),u-1);let s=null;for(const[e,a]of Object.entries(n.value))if(a===r&&e!==t){s=e;break}if(w.value!==s&&(w.value=s),v){const n=Date.now();n-D.value>50&&(runOnJS(v)(t,s,Math.round(e)),D.value=n)}A.value=e,setPosition(e,u,n,t,o),setAutoScroll(e,a.value,M.value,o,l)}),[g,o,u,n,t,v,a,M,l,w,A,D]),useAnimatedReaction((()=>n.value[t]),((e,n)=>{null!==e&&null!==n&&e!==n&&(g.value||(A.value=withSpring(e*o),r&&runOnJS(r)(t,n,e)))}),[g]),useAnimatedReaction((()=>l.value),((e,t)=>{if(null!==e&&null!==t&&e!==t)switch(e){case ScrollDirection.Up:O.value=a.value,O.value=withTiming(0,{duration:1500});break;case ScrollDirection.Down:{const e=u*o-R;O.value=a.value,O.value=withTiming(e,{duration:1500});break}case ScrollDirection.None:O.value=a.value}})),useAnimatedReaction((()=>O.value),((e,t)=>{null!==e&&null!==t&&e!==t&&g.value&&(a.value=e)}),[g]);const x=useAnimatedGestureHandler({onStart(e,l){l.initialItemContentY=n.value[t]*o,l.initialFingerAbsoluteY=e.absoluteY,l.initialLowerBound=a.value,b.value=l.initialItemContentY,g.value=!0,runOnJS(m)(!0),s&&runOnJS(s)(t,n.value[t])},onActive(e,t){const n=e.absoluteY-t.initialFingerAbsoluteY,l=a.value-t.initialLowerBound;b.value=t.initialItemContentY+n+l},onFinish(){const e=n.value[t]*o;A.value=withTiming(e),g.value=!1,runOnJS(m)(!1),c&&runOnJS(c)(t,n.value[t]),w.value=null}});return{animatedStyle:useAnimatedStyle((()=>({position:"absolute",left:0,right:0,top:A.value,zIndex:g.value?1:0,backgroundColor:"#000000",shadowColor:"black",shadowOpacity:withSpring(g.value?.2:0),shadowRadius:10})),[g]),panGestureHandler:x,isMoving:h,hasHandle:f}}
1
+ import{useState,useRef,useEffect}from"react";import React from"react";import{runOnJS,runOnUI,useAnimatedGestureHandler,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";export var ScrollDirection;(function(ScrollDirection){ScrollDirection["None"]="none";ScrollDirection["Up"]="up";ScrollDirection["Down"]="down"})(ScrollDirection||(ScrollDirection={}));export function clamp(value,lowerBound,upperBound){"worklet";return Math.max(lowerBound,Math.min(value,upperBound))}export function objectMove(object,from,to){"worklet";const newObject=Object.assign({},object);for(const id in object){if(object[id]===from){newObject[id]=to}if(object[id]===to){newObject[id]=from}}return newObject}export function listToObject(list){const values=Object.values(list);const object={};for(let i=0;i<values.length;i++){object[values[i].id]=i}return object}export function setPosition(positionY,itemsCount,positions,id,itemHeight){"worklet";const newPosition=clamp(Math.floor(positionY/itemHeight),0,itemsCount-1);if(newPosition!==positions.value[id]){positions.value=objectMove(positions.value,positions.value[id],newPosition)}}export function setAutoScroll(positionY,lowerBound,upperBound,scrollThreshold,autoScroll){"worklet";if(positionY<=lowerBound+scrollThreshold){autoScroll.value=ScrollDirection.Up}else if(positionY>=upperBound-scrollThreshold){autoScroll.value=ScrollDirection.Down}else{autoScroll.value=ScrollDirection.None}}export function useSortable(options){const{id,positions,lowerBound,autoScrollDirection,itemsCount,itemHeight,containerHeight=500,onMove,onDragStart,onDrop,onDragging,children,handleComponent}=options;const[isMoving,setIsMoving]=useState(false);const[hasHandle,setHasHandle]=useState(false);const movingSV=useSharedValue(false);const currentOverItemId=useSharedValue(null);const onDraggingLastCallTimestamp=useSharedValue(0);const THROTTLE_INTERVAL=50;const positionY=useSharedValue(0);const top=useSharedValue(0);const targetLowerBound=useSharedValue(0);useEffect((()=>{runOnUI((()=>{"worklet";const initialTopVal=positions.value[id]*itemHeight;const initialLowerBoundVal=lowerBound.value;top.value=initialTopVal;positionY.value=initialTopVal;targetLowerBound.value=initialLowerBoundVal}))()}),[]);const calculatedContainerHeight=useRef(containerHeight).current;const upperBound=useDerivedValue((()=>lowerBound.value+calculatedContainerHeight));useEffect((()=>{if(!children||!handleComponent){setHasHandle(false);return}const checkForHandle=child=>{if(React.isValidElement(child)){if(child.type===handleComponent){return true}if(child.props&&child.props.children){if(React.Children.toArray(child.props.children).some(checkForHandle)){return true}}}return false};setHasHandle(React.Children.toArray(children).some(checkForHandle))}),[children,handleComponent]);useAnimatedReaction((()=>positionY.value),((currentY,previousY)=>{if(currentY===null||!movingSV.value){return}if(previousY!==null&&currentY===previousY){return}const clampedPosition=Math.min(Math.max(0,Math.ceil(currentY/itemHeight)),itemsCount-1);let newOverItemId=null;for(const[itemIdIter,itemPosIter]of Object.entries(positions.value)){if(itemPosIter===clampedPosition&&itemIdIter!==id){newOverItemId=itemIdIter;break}}if(currentOverItemId.value!==newOverItemId){currentOverItemId.value=newOverItemId}if(onDragging){const now=Date.now();if(now-onDraggingLastCallTimestamp.value>THROTTLE_INTERVAL){runOnJS(onDragging)(id,newOverItemId,Math.round(currentY));onDraggingLastCallTimestamp.value=now}}top.value=currentY;setPosition(currentY,itemsCount,positions,id,itemHeight);setAutoScroll(currentY,lowerBound.value,upperBound.value,itemHeight,autoScrollDirection)}),[movingSV,itemHeight,itemsCount,positions,id,onDragging,lowerBound,upperBound,autoScrollDirection,currentOverItemId,top,onDraggingLastCallTimestamp]);useAnimatedReaction((()=>positions.value[id]),((currentPosition,previousPosition)=>{if(currentPosition!==null&&previousPosition!==null&&currentPosition!==previousPosition){if(!movingSV.value){top.value=withSpring(currentPosition*itemHeight);if(onMove){runOnJS(onMove)(id,previousPosition,currentPosition)}}}}),[movingSV]);useAnimatedReaction((()=>autoScrollDirection.value),((scrollDirection,previousValue)=>{if(scrollDirection!==null&&previousValue!==null&&scrollDirection!==previousValue){switch(scrollDirection){case ScrollDirection.Up:{targetLowerBound.value=lowerBound.value;targetLowerBound.value=withTiming(0,{duration:1500});break}case ScrollDirection.Down:{const contentHeight=itemsCount*itemHeight;const maxScroll=contentHeight-calculatedContainerHeight;targetLowerBound.value=lowerBound.value;targetLowerBound.value=withTiming(maxScroll,{duration:1500});break}case ScrollDirection.None:{targetLowerBound.value=lowerBound.value;break}}}}));useAnimatedReaction((()=>targetLowerBound.value),((targetLowerBoundValue,previousValue)=>{if(targetLowerBoundValue!==null&&previousValue!==null&&targetLowerBoundValue!==previousValue){if(movingSV.value){lowerBound.value=targetLowerBoundValue}}}),[movingSV]);const panGestureHandler=useAnimatedGestureHandler({onStart(event,ctx){"worklet";ctx.initialItemContentY=positions.value[id]*itemHeight;ctx.initialFingerAbsoluteY=event.absoluteY;ctx.initialLowerBound=lowerBound.value;positionY.value=ctx.initialItemContentY;movingSV.value=true;runOnJS(setIsMoving)(true);if(onDragStart){runOnJS(onDragStart)(id,positions.value[id])}},onActive(event,ctx){"worklet";const fingerDyScreen=event.absoluteY-ctx.initialFingerAbsoluteY;const scrollDeltaSinceStart=lowerBound.value-ctx.initialLowerBound;positionY.value=ctx.initialItemContentY+fingerDyScreen+scrollDeltaSinceStart},onFinish(){"worklet";const finishPosition=positions.value[id]*itemHeight;top.value=withTiming(finishPosition);movingSV.value=false;runOnJS(setIsMoving)(false);if(onDrop){runOnJS(onDrop)(id,positions.value[id])}currentOverItemId.value=null}});const animatedStyle=useAnimatedStyle((()=>{"worklet";return{position:"absolute",left:0,right:0,top:top.value,zIndex:movingSV.value?1:0,backgroundColor:"#000000",shadowColor:"black",shadowOpacity:withSpring(movingSV.value?.2:0),shadowRadius:10}}),[movingSV]);return{animatedStyle,panGestureHandler,isMoving,hasHandle}}
@@ -1 +1 @@
1
- import{useRef,useCallback}from"react";import{scrollTo,useAnimatedReaction,useAnimatedRef,useAnimatedScrollHandler,useSharedValue}from"react-native-reanimated";import{listToObject}from"../components/sortableUtils";import{ScrollDirection}from"../types/sortable";export function useSortableList(e){const{data:t,itemHeight:o,itemKeyExtractor:l=e=>e.id}=e,r=useSharedValue(listToObject(t)),i=useSharedValue(0),a=useSharedValue(ScrollDirection.None),n=useAnimatedRef(),s=useRef(null);useAnimatedReaction((()=>i.value),(e=>{scrollTo(n,0,e,!1)}));const u=useAnimatedScrollHandler((e=>{i.value=e.contentOffset.y})),c=useCallback((()=>{let e=null;e&&clearTimeout(e),e=setTimeout((()=>{var e;null===(e=s.current)||void 0===e||e.requestPositionUpdate()}),50)}),[]),d=t.length*o,m=useCallback(((e,n)=>({id:l(e,n),positions:r,lowerBound:i,autoScrollDirection:a,itemsCount:t.length,itemHeight:o})),[t.length,o,l,r,i,a]);return{positions:r,scrollY:i,autoScroll:a,scrollViewRef:n,dropProviderRef:s,handleScroll:u,handleScrollEnd:c,contentHeight:d,getItemProps:m}}
1
+ import{useRef,useCallback}from"react";import{scrollTo,useAnimatedReaction,useAnimatedRef,useAnimatedScrollHandler,useSharedValue}from"react-native-reanimated";import{listToObject}from"../components/sortableUtils";import{ScrollDirection}from"../types/sortable";export function useSortableList(options){const{data,itemHeight,itemKeyExtractor=item=>item.id}=options;const positions=useSharedValue(listToObject(data));const scrollY=useSharedValue(0);const autoScroll=useSharedValue(ScrollDirection.None);const scrollViewRef=useAnimatedRef();const dropProviderRef=useRef(null);useAnimatedReaction((()=>scrollY.value),(scrolling=>{scrollTo(scrollViewRef,0,scrolling,false)}));const handleScroll=useAnimatedScrollHandler((event=>{scrollY.value=event.contentOffset.y}));const handleScrollEnd=useCallback((()=>{let localScrollTimeout=null;if(localScrollTimeout){clearTimeout(localScrollTimeout)}localScrollTimeout=setTimeout((()=>{var _a;(_a=dropProviderRef.current)===null||_a===void 0?void 0:_a.requestPositionUpdate()}),50)}),[]);const contentHeight=data.length*itemHeight;const getItemProps=useCallback(((item,index)=>{const id=itemKeyExtractor(item,index);return{id,positions,lowerBound:scrollY,autoScrollDirection:autoScroll,itemsCount:data.length,itemHeight}}),[data.length,itemHeight,itemKeyExtractor,positions,scrollY,autoScroll]);return{positions,scrollY,autoScroll,scrollViewRef,dropProviderRef,handleScroll,handleScrollEnd,contentHeight,getItemProps}}
@@ -1 +1 @@
1
- import{createContext}from"react";const defaultSlotsContextValue={register:(e,t)=>{process.env.NODE_ENV},unregister:e=>{process.env.NODE_ENV},getSlots:()=>(process.env.NODE_ENV,{}),isRegistered:e=>(process.env.NODE_ENV,!1),setActiveHoverSlot:e=>{process.env.NODE_ENV},activeHoverSlotId:null,registerPositionUpdateListener:(e,t)=>{process.env.NODE_ENV},unregisterPositionUpdateListener:e=>{process.env.NODE_ENV},requestPositionUpdate:()=>{process.env.NODE_ENV},registerDroppedItem:(e,t,s)=>{process.env.NODE_ENV},unregisterDroppedItem:e=>{process.env.NODE_ENV},getDroppedItems:()=>(process.env.NODE_ENV,{}),hasAvailableCapacity:e=>(process.env.NODE_ENV,!1),onDragging:e=>{process.env.NODE_ENV},onDragStart:void 0,onDragEnd:void 0};export const SlotsContext=createContext(defaultSlotsContextValue);
1
+ import{createContext}from"react";const defaultSlotsContextValue={register:(_id,_slot)=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: register called without a Provider.")}},unregister:_id=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: unregister called without a Provider.")}},getSlots:()=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: getSlots called without a Provider.")}return{}},isRegistered:_id=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: isRegistered called without a Provider.")}return false},setActiveHoverSlot:_id=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: setActiveHoverSlot called without a Provider.")}},activeHoverSlotId:null,registerPositionUpdateListener:(_id,_listener)=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: registerPositionUpdateListener called without a Provider.")}},unregisterPositionUpdateListener:_id=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: unregisterPositionUpdateListener called without a Provider.")}},requestPositionUpdate:()=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: requestPositionUpdate called without a Provider (internally).")}},registerDroppedItem:(_draggableId,_droppableId,_itemData)=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: registerDroppedItem called without a Provider.")}},unregisterDroppedItem:_draggableId=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: unregisterDroppedItem called without a Provider.")}},getDroppedItems:()=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: getDroppedItems called without a Provider.")}return{}},hasAvailableCapacity:_droppableId=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: hasAvailableCapacity called without a Provider.")}return false},onDragging:payload=>{if(process.env.NODE_ENV!=="production"){console.warn("SlotsContext: onDragging called without a Provider.")}},onDragStart:undefined,onDragEnd:undefined};export const SlotsContext=createContext(defaultSlotsContextValue);
@@ -1 +1 @@
1
- export var DraggableState;!function(D){D.IDLE="IDLE",D.DRAGGING="DRAGGING",D.DROPPED="DROPPED"}(DraggableState||(DraggableState={}));
1
+ export var DraggableState;(function(DraggableState){DraggableState["IDLE"]="IDLE";DraggableState["DRAGGING"]="DRAGGING";DraggableState["DROPPED"]="DROPPED"})(DraggableState||(DraggableState={}));
@@ -1 +1 @@
1
- export var ScrollDirection;!function(o){o.None="none",o.Up="up",o.Down="down"}(ScrollDirection||(ScrollDirection={}));
1
+ export var ScrollDirection;(function(ScrollDirection){ScrollDirection["None"]="none";ScrollDirection["Up"]="up";ScrollDirection["Down"]="down"})(ScrollDirection||(ScrollDirection={}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-reanimated-dnd",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "A powerful drag-and-drop library for React Native using Reanimated 3",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.js",
@@ -16,7 +16,9 @@
16
16
  "sideEffects": false,
17
17
  "scripts": {
18
18
  "build": "tsc && npm run minify",
19
+ "build:safe": "tsc",
19
20
  "build:clean": "rm -rf lib && npm run build",
21
+ "build:clean:safe": "rm -rf lib && npm run build:safe",
20
22
  "minify": "node scripts/build.js",
21
23
  "type-check": "tsc --noEmit",
22
24
  "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md,yml,yaml}\" --ignore-path .prettierignore",