@btfash/react-native-reanimated-dnd 1.1.0 → 1.1.1
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.
- package/lib/components/Draggable.d.ts +5 -5
- package/lib/components/Droppable.d.ts +3 -3
- package/lib/components/Sortable.d.ts +3 -3
- package/lib/components/Sortable.js +1 -1
- package/lib/components/SortableItem.d.ts +6 -6
- package/lib/components/sortableUtils.d.ts +33 -33
- package/lib/components/sortableUtils.js +1 -1
- package/lib/context/DropContext.d.ts +3 -3
- package/lib/context/DropContext.js +1 -1
- package/lib/hooks/index.d.ts +6 -6
- package/lib/hooks/useDraggable.d.ts +2 -2
- package/lib/hooks/useDraggable.js +1 -1
- package/lib/hooks/useDroppable.d.ts +2 -2
- package/lib/hooks/useDroppable.js +1 -1
- package/lib/hooks/useHorizontalSortable.d.ts +2 -2
- package/lib/hooks/useHorizontalSortable.js +1 -1
- package/lib/hooks/useHorizontalSortableList.d.ts +4 -4
- package/lib/hooks/useHorizontalSortableList.js +1 -1
- package/lib/hooks/useSortable.d.ts +50 -50
- package/lib/hooks/useSortable.js +1 -1
- package/lib/hooks/useSortableList.d.ts +27 -27
- package/lib/hooks/useSortableList.js +1 -1
- package/lib/index.d.ts +13 -13
- package/lib/types/context.d.ts +67 -67
- package/lib/types/draggable.d.ts +54 -54
- package/lib/types/droppable.d.ts +26 -26
- package/lib/types/index.d.ts +4 -4
- package/lib/types/sortable.d.ts +233 -233
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { DraggableHandleProps, DraggableProps } from "../types/draggable";
|
|
3
|
-
export declare const Draggable: (<TData = unknown>({ style: componentStyle, children, ...useDraggableHookOptions }: DraggableProps<TData>) => React.JSX.Element) & {
|
|
4
|
-
Handle: ({ children, style }: DraggableHandleProps) => React.JSX.Element;
|
|
5
|
-
};
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DraggableHandleProps, DraggableProps } from "../types/draggable";
|
|
3
|
+
export declare const Draggable: (<TData = unknown>({ style: componentStyle, children, ...useDraggableHookOptions }: DraggableProps<TData>) => React.JSX.Element) & {
|
|
4
|
+
Handle: ({ children, style }: DraggableHandleProps) => React.JSX.Element;
|
|
5
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { DroppableProps } from "../types/droppable";
|
|
3
|
-
export declare const Droppable: <TData = unknown>({ onDrop, dropDisabled, onActiveChange, dropAlignment, dropOffset, activeStyle, droppableId, capacity, style, children, }: DroppableProps<TData>) => React.ReactElement;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DroppableProps } from "../types/droppable";
|
|
3
|
+
export declare const Droppable: <TData = unknown>({ onDrop, dropDisabled, onActiveChange, dropAlignment, dropOffset, activeStyle, droppableId, capacity, style, children, }: DroppableProps<TData>) => React.ReactElement;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { SortableProps } from "../types/sortable";
|
|
3
|
-
export declare const Sortable: React.MemoExoticComponent<({ data, renderItem, ...props }: SortableProps<any>) => React.JSX.Element>;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SortableProps } from "../types/sortable";
|
|
3
|
+
export declare const Sortable: React.MemoExoticComponent<({ data, renderItem, ...props }: SortableProps<any>) => React.JSX.Element>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{memo,useCallback}from"react";import{StyleSheet}from"react-native";import Animated from"react-native-reanimated";import{GestureHandlerRootView,FlatList,ScrollView}from"react-native-gesture-handler";import{DropProvider}from"../context/DropContext";import{SortableDirection}from"../types/sortable";import{useSortableList}from"../hooks/useSortableList";import{useHorizontalSortableList}from"../hooks/useHorizontalSortableList";import{dataHash}from"./sortableUtils";const AnimatedFlatList=Animated.createAnimatedComponent(FlatList);const AnimatedScrollView=Animated.createAnimatedComponent(ScrollView);function SortableComponent({data,renderItem,direction=SortableDirection.Vertical,itemHeight,itemWidth,gap=0,paddingHorizontal=0,style,contentContainerStyle,itemKeyExtractor=item=>item.id,useFlatList=true}){if(direction===SortableDirection.Vertical&&!itemHeight){throw new Error("itemHeight is required when direction is vertical")}if(direction===SortableDirection.Horizontal&&!itemWidth){throw new Error("itemWidth is required when direction is horizontal")}if(direction===SortableDirection.Horizontal){const horizontalOptions={data,itemWidth,gap,paddingHorizontal,itemKeyExtractor};const{scrollViewRef:horizontalScrollViewRef,dropProviderRef:horizontalDropProviderRef,handleScroll:horizontalHandleScroll,handleScrollEnd:horizontalHandleScrollEnd,contentWidth,getItemProps:getHorizontalItemProps}=useHorizontalSortableList(horizontalOptions);const memoizedHorizontalRenderItem=useCallback((
|
|
1
|
+
import React,{memo,useCallback}from"react";import{StyleSheet}from"react-native";import Animated from"react-native-reanimated";import{GestureHandlerRootView,FlatList,ScrollView}from"react-native-gesture-handler";import{DropProvider}from"../context/DropContext";import{SortableDirection}from"../types/sortable";import{useSortableList}from"../hooks/useSortableList";import{useHorizontalSortableList}from"../hooks/useHorizontalSortableList";import{dataHash}from"./sortableUtils";const AnimatedFlatList=Animated.createAnimatedComponent(FlatList);const AnimatedScrollView=Animated.createAnimatedComponent(ScrollView);function SortableComponent({data,renderItem,direction=SortableDirection.Vertical,itemHeight,itemWidth,gap=0,paddingHorizontal=0,style,contentContainerStyle,itemKeyExtractor=item=>item.id,useFlatList=true}){if(direction===SortableDirection.Vertical&&!itemHeight){throw new Error("itemHeight is required when direction is vertical")}if(direction===SortableDirection.Horizontal&&!itemWidth){throw new Error("itemWidth is required when direction is horizontal")}if(direction===SortableDirection.Horizontal){const horizontalOptions={data,itemWidth,gap,paddingHorizontal,itemKeyExtractor};const{scrollViewRef:horizontalScrollViewRef,dropProviderRef:horizontalDropProviderRef,handleScroll:horizontalHandleScroll,handleScrollEnd:horizontalHandleScrollEnd,contentWidth,getItemProps:getHorizontalItemProps}=useHorizontalSortableList(horizontalOptions);const memoizedHorizontalRenderItem=useCallback(({item,index})=>{const itemProps=getHorizontalItemProps(item,index);const sortableItemProps={item,index,direction:SortableDirection.Horizontal,autoScrollHorizontalDirection:itemProps.autoScrollDirection,...itemProps};return renderItem(sortableItemProps)},[getHorizontalItemProps,renderItem]);return React.createElement(GestureHandlerRootView,{style:styles.flex},React.createElement(DropProvider,{ref:horizontalDropProviderRef},useFlatList?React.createElement(AnimatedFlatList,{ref:horizontalScrollViewRef,data,keyExtractor:itemKeyExtractor,horizontal:true,renderItem:memoizedHorizontalRenderItem,onScroll:horizontalHandleScroll,scrollEventThrottle:16,style:[styles.scrollView,style],contentContainerStyle:[{width:contentWidth},contentContainerStyle],onScrollEndDrag:horizontalHandleScrollEnd,onMomentumScrollEnd:horizontalHandleScrollEnd,simultaneousHandlers:horizontalDropProviderRef,showsHorizontalScrollIndicator:false}):React.createElement(AnimatedScrollView,{ref:horizontalScrollViewRef,onScroll:horizontalHandleScroll,scrollEventThrottle:16,horizontal:true,style:[styles.scrollView,style],contentContainerStyle:[{width:contentWidth},contentContainerStyle],onScrollEndDrag:horizontalHandleScrollEnd,onMomentumScrollEnd:horizontalHandleScrollEnd,simultaneousHandlers:horizontalDropProviderRef,showsHorizontalScrollIndicator:false},data.map((item,index)=>{const itemProps=getHorizontalItemProps(item,index);const sortableItemProps={item,index,direction:SortableDirection.Horizontal,autoScrollHorizontalDirection:itemProps.autoScrollDirection,...itemProps};return renderItem(sortableItemProps)}))))}const verticalOptions={data,itemHeight,itemKeyExtractor};const{scrollViewRef,dropProviderRef,handleScroll,handleScrollEnd,contentHeight,getItemProps}=useSortableList(verticalOptions);const memoizedVerticalRenderItem=useCallback(({item,index})=>{const itemProps=getItemProps(item,index);const sortableItemProps={item,index,direction:SortableDirection.Vertical,...itemProps};return renderItem(sortableItemProps)},[getItemProps,renderItem]);return React.createElement(GestureHandlerRootView,{style:styles.flex},React.createElement(DropProvider,{ref:dropProviderRef},useFlatList?React.createElement(AnimatedFlatList,{ref:scrollViewRef,data,keyExtractor:itemKeyExtractor,renderItem:memoizedVerticalRenderItem,onScroll:handleScroll,scrollEventThrottle:16,style:[styles.scrollView,style],contentContainerStyle:[{height:contentHeight},contentContainerStyle],onScrollEndDrag:handleScrollEnd,onMomentumScrollEnd:handleScrollEnd,simultaneousHandlers:dropProviderRef,showsVerticalScrollIndicator:false}):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,direction:SortableDirection.Vertical,...itemProps};return renderItem(sortableItemProps)}))))}export const Sortable=memo(({data,renderItem,...props})=>{const dataHashKey=dataHash(data);return React.createElement(SortableComponent,{data,renderItem,...props,key:dataHashKey})});const styles=StyleSheet.create({flex:{flex:1},scrollView:{flex:1,position:"relative",backgroundColor:"white"}});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { SortableItemProps, SortableHandleProps } from "../types/sortable";
|
|
3
|
-
export declare function SortableItem<T>({ id, data, positions, direction, lowerBound, leftBound, autoScrollDirection, autoScrollHorizontalDirection, itemsCount, itemHeight, itemWidth, gap, paddingHorizontal, containerHeight, containerWidth, children, style, animatedStyle: customAnimatedStyle, onMove, onDragStart, onDrop, onDragging, onDraggingHorizontal, }: SortableItemProps<T>): React.JSX.Element;
|
|
4
|
-
export declare namespace SortableItem {
|
|
5
|
-
var Handle: ({ children, style }: SortableHandleProps) => React.JSX.Element;
|
|
6
|
-
}
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SortableItemProps, SortableHandleProps } from "../types/sortable";
|
|
3
|
+
export declare function SortableItem<T>({ id, data, positions, direction, lowerBound, leftBound, autoScrollDirection, autoScrollHorizontalDirection, itemsCount, itemHeight, itemWidth, gap, paddingHorizontal, containerHeight, containerWidth, children, style, animatedStyle: customAnimatedStyle, onMove, onDragStart, onDrop, onDragging, onDraggingHorizontal, }: SortableItemProps<T>): React.JSX.Element;
|
|
4
|
+
export declare namespace SortableItem {
|
|
5
|
+
var Handle: ({ children, style }: SortableHandleProps) => React.JSX.Element;
|
|
6
|
+
}
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { SharedValue } from "react-native-reanimated";
|
|
2
|
-
export declare enum ScrollDirection {
|
|
3
|
-
None = "none",
|
|
4
|
-
Up = "up",
|
|
5
|
-
Down = "down"
|
|
6
|
-
}
|
|
7
|
-
export declare enum HorizontalScrollDirection {
|
|
8
|
-
None = "none",
|
|
9
|
-
Left = "left",
|
|
10
|
-
Right = "right"
|
|
11
|
-
}
|
|
12
|
-
export declare function clamp(value: number, lowerBound: number, upperBound: number): number;
|
|
13
|
-
export declare function objectMove(object: {
|
|
14
|
-
[id: string]: number;
|
|
15
|
-
}, from: number, to: number): {
|
|
16
|
-
[id: string]: number;
|
|
17
|
-
};
|
|
18
|
-
export declare function listToObject<T extends {
|
|
19
|
-
id: string;
|
|
20
|
-
}>(list: T[]): {
|
|
21
|
-
[id: string]: number;
|
|
22
|
-
};
|
|
23
|
-
export declare function setPosition(positionY: number, itemsCount: number, positions: SharedValue<{
|
|
24
|
-
[id: string]: number;
|
|
25
|
-
}>, id: string, itemHeight: number): void;
|
|
26
|
-
export declare function setAutoScroll(positionY: number, lowerBound: number, upperBound: number, scrollThreshold: number, autoScroll: SharedValue<ScrollDirection>): void;
|
|
27
|
-
export declare function getItemXPosition(position: number, itemWidth: number, gap?: number, paddingHorizontal?: number): number;
|
|
28
|
-
export declare function getContentWidth(itemsCount: number, itemWidth: number, gap?: number, paddingHorizontal?: number): number;
|
|
29
|
-
export declare function setHorizontalPosition(positionX: number, itemsCount: number, positions: SharedValue<{
|
|
30
|
-
[id: string]: number;
|
|
31
|
-
}>, id: string, itemWidth: number, gap?: number, paddingHorizontal?: number): void;
|
|
32
|
-
export declare function setHorizontalAutoScroll(positionX: number, leftBound: number, rightBound: number, scrollThreshold: number, autoScrollDirection: SharedValue<HorizontalScrollDirection>): void;
|
|
33
|
-
export declare const dataHash: (data: any[]) => string;
|
|
1
|
+
import { SharedValue } from "react-native-reanimated";
|
|
2
|
+
export declare enum ScrollDirection {
|
|
3
|
+
None = "none",
|
|
4
|
+
Up = "up",
|
|
5
|
+
Down = "down"
|
|
6
|
+
}
|
|
7
|
+
export declare enum HorizontalScrollDirection {
|
|
8
|
+
None = "none",
|
|
9
|
+
Left = "left",
|
|
10
|
+
Right = "right"
|
|
11
|
+
}
|
|
12
|
+
export declare function clamp(value: number, lowerBound: number, upperBound: number): number;
|
|
13
|
+
export declare function objectMove(object: {
|
|
14
|
+
[id: string]: number;
|
|
15
|
+
}, from: number, to: number): {
|
|
16
|
+
[id: string]: number;
|
|
17
|
+
};
|
|
18
|
+
export declare function listToObject<T extends {
|
|
19
|
+
id: string;
|
|
20
|
+
}>(list: T[]): {
|
|
21
|
+
[id: string]: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function setPosition(positionY: number, itemsCount: number, positions: SharedValue<{
|
|
24
|
+
[id: string]: number;
|
|
25
|
+
}>, id: string, itemHeight: number): void;
|
|
26
|
+
export declare function setAutoScroll(positionY: number, lowerBound: number, upperBound: number, scrollThreshold: number, autoScroll: SharedValue<ScrollDirection>): void;
|
|
27
|
+
export declare function getItemXPosition(position: number, itemWidth: number, gap?: number, paddingHorizontal?: number): number;
|
|
28
|
+
export declare function getContentWidth(itemsCount: number, itemWidth: number, gap?: number, paddingHorizontal?: number): number;
|
|
29
|
+
export declare function setHorizontalPosition(positionX: number, itemsCount: number, positions: SharedValue<{
|
|
30
|
+
[id: string]: number;
|
|
31
|
+
}>, id: string, itemWidth: number, gap?: number, paddingHorizontal?: number): void;
|
|
32
|
+
export declare function setHorizontalAutoScroll(positionX: number, leftBound: number, rightBound: number, scrollThreshold: number, autoScrollDirection: SharedValue<HorizontalScrollDirection>): void;
|
|
33
|
+
export declare const dataHash: (data: any[]) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export var ScrollDirection;(function(ScrollDirection){ScrollDirection["None"]="none";ScrollDirection["Up"]="up";ScrollDirection["Down"]="down"})(ScrollDirection||(ScrollDirection={}));export var HorizontalScrollDirection;(function(HorizontalScrollDirection){HorizontalScrollDirection["None"]="none";HorizontalScrollDirection["Left"]="left";HorizontalScrollDirection["Right"]="right"})(HorizontalScrollDirection||(HorizontalScrollDirection={}));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 getItemXPosition(position,itemWidth,gap=0,paddingHorizontal=0){"worklet";return paddingHorizontal+position*(itemWidth+gap)}export function getContentWidth(itemsCount,itemWidth,gap=0,paddingHorizontal=0){"worklet";if(itemsCount===0){return paddingHorizontal*2}const totalItemsWidth=itemsCount*itemWidth;const totalGaps=Math.max(0,itemsCount-1)*gap;return totalItemsWidth+totalGaps+paddingHorizontal*2}export function setHorizontalPosition(positionX,itemsCount,positions,id,itemWidth,gap=0,paddingHorizontal=0){"worklet";const adjustedX=positionX-paddingHorizontal;const itemWithGapWidth=itemWidth+gap;const newPosition=clamp(Math.floor(adjustedX/itemWithGapWidth),0,itemsCount-1);if(newPosition!==positions.value[id]){positions.value=objectMove(positions.value,positions.value[id],newPosition)}}export function setHorizontalAutoScroll(positionX,leftBound,rightBound,scrollThreshold,autoScrollDirection){"worklet";const effectiveThreshold=Math.max(scrollThreshold,60);const leftEdge=leftBound+effectiveThreshold;const rightEdge=rightBound-effectiveThreshold;if(positionX<leftEdge){autoScrollDirection.value=HorizontalScrollDirection.Left}else if(positionX>rightEdge){autoScrollDirection.value=HorizontalScrollDirection.Right}else{autoScrollDirection.value=HorizontalScrollDirection.None}}export const dataHash=data=>{const str=data.reduce((
|
|
1
|
+
export var ScrollDirection;(function(ScrollDirection){ScrollDirection["None"]="none";ScrollDirection["Up"]="up";ScrollDirection["Down"]="down"})(ScrollDirection||(ScrollDirection={}));export var HorizontalScrollDirection;(function(HorizontalScrollDirection){HorizontalScrollDirection["None"]="none";HorizontalScrollDirection["Left"]="left";HorizontalScrollDirection["Right"]="right"})(HorizontalScrollDirection||(HorizontalScrollDirection={}));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 getItemXPosition(position,itemWidth,gap=0,paddingHorizontal=0){"worklet";return paddingHorizontal+position*(itemWidth+gap)}export function getContentWidth(itemsCount,itemWidth,gap=0,paddingHorizontal=0){"worklet";if(itemsCount===0){return paddingHorizontal*2}const totalItemsWidth=itemsCount*itemWidth;const totalGaps=Math.max(0,itemsCount-1)*gap;return totalItemsWidth+totalGaps+paddingHorizontal*2}export function setHorizontalPosition(positionX,itemsCount,positions,id,itemWidth,gap=0,paddingHorizontal=0){"worklet";const adjustedX=positionX-paddingHorizontal;const itemWithGapWidth=itemWidth+gap;const newPosition=clamp(Math.floor(adjustedX/itemWithGapWidth),0,itemsCount-1);if(newPosition!==positions.value[id]){positions.value=objectMove(positions.value,positions.value[id],newPosition)}}export function setHorizontalAutoScroll(positionX,leftBound,rightBound,scrollThreshold,autoScrollDirection){"worklet";const effectiveThreshold=Math.max(scrollThreshold,60);const leftEdge=leftBound+effectiveThreshold;const rightEdge=rightBound-effectiveThreshold;if(positionX<leftEdge){autoScrollDirection.value=HorizontalScrollDirection.Left}else if(positionX>rightEdge){autoScrollDirection.value=HorizontalScrollDirection.Right}else{autoScrollDirection.value=HorizontalScrollDirection.None}}export const dataHash=data=>{const str=data.reduce((acc,item)=>acc+item.id,"");let hash=0;for(let i=0,len=str.length;i<len;i++){let chr=str.charCodeAt(i);hash=(hash<<5)-hash+chr;hash|=0}return hash.toString()};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { DropProviderProps, DropProviderRef } from "../types/context";
|
|
3
|
-
export declare const DropProvider: React.ForwardRefExoticComponent<DropProviderProps & React.RefAttributes<DropProviderRef>>;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DropProviderProps, DropProviderRef } from "../types/context";
|
|
3
|
+
export declare const DropProvider: React.ForwardRefExoticComponent<DropProviderProps & React.RefAttributes<DropProviderRef>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useRef,useState,useMemo,useCallback,forwardRef,useImperativeHandle,useEffect}from"react";import{SlotsContext}from"../types/context";export const DropProvider=forwardRef((
|
|
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";
|
package/lib/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { useSortable } from "./useSortable";
|
|
2
|
-
export { useSortableList } from "./useSortableList";
|
|
3
|
-
export { useHorizontalSortable } from "./useHorizontalSortable";
|
|
4
|
-
export { useHorizontalSortableList } from "./useHorizontalSortableList";
|
|
5
|
-
export { useDraggable } from "./useDraggable";
|
|
6
|
-
export { useDroppable } from "./useDroppable";
|
|
1
|
+
export { useSortable } from "./useSortable";
|
|
2
|
+
export { useSortableList } from "./useSortableList";
|
|
3
|
+
export { useHorizontalSortable } from "./useHorizontalSortable";
|
|
4
|
+
export { useHorizontalSortableList } from "./useHorizontalSortableList";
|
|
5
|
+
export { useDraggable } from "./useDraggable";
|
|
6
|
+
export { useDroppable } from "./useDroppable";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { UseDraggableOptions, UseDraggableReturn } from "../types/draggable";
|
|
2
|
-
export declare const useDraggable: <TData = unknown>(options: UseDraggableOptions<TData>) => UseDraggableReturn;
|
|
1
|
+
import { UseDraggableOptions, UseDraggableReturn } from "../types/draggable";
|
|
2
|
+
export declare const useDraggable: <TData = unknown>(options: UseDraggableOptions<TData>) => UseDraggableReturn;
|
|
@@ -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=options=>{const{data,draggableId,dragDisabled=false,preDragDelay=0,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}const props=child.props;if(child.props&&props.children){if(React.Children.toArray(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 preDragDelayShared=useSharedValue(preDragDelay);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((()=>{preDragDelayShared.value=preDragDelay}),[preDragDelay,preDragDelayShared]);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&¤tTy===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&¤tTy===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){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().activateAfterLongPress(preDragDelay).onStart((()=>{"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,preDragDelay]);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
|
+
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,preDragDelay=0,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}const props=child.props;if(child.props&&props.children){if(React.Children.toArray(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 preDragDelayShared=useSharedValue(preDragDelay);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(()=>{preDragDelayShared.value=preDragDelay},[preDragDelay,preDragDelayShared]);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&¤tTy===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&¤tTy===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){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().activateAfterLongPress(preDragDelay).onStart(()=>{"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,preDragDelay]);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,2 +1,2 @@
|
|
|
1
|
-
import { UseDroppableOptions, UseDroppableReturn } from "../types/droppable";
|
|
2
|
-
export declare const useDroppable: <TData = unknown>(options: UseDroppableOptions<TData>) => UseDroppableReturn;
|
|
1
|
+
import { UseDroppableOptions, UseDroppableReturn } from "../types/droppable";
|
|
2
|
+
export declare const useDroppable: <TData = unknown>(options: UseDroppableOptions<TData>) => UseDroppableReturn;
|
|
@@ -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";let _nextDroppableId=1;const _getUniqueDroppableId=()=>_nextDroppableId++;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((
|
|
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";let _nextDroppableId=1;const _getUniqueDroppableId=()=>_nextDroppableId++;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]);const registerWithMeasurement=useCallback((pageX,pageY,width,height)=>{register(id,{id:droppableId||`droppable-${id}`,x:pageX,y:pageY,width,height,onDrop,dropAlignment:dropAlignment||"center",dropOffset:dropOffset||{x:0,y:0},capacity})},[id,droppableId,onDrop,register,dropAlignment,dropOffset,capacity]);const updateDroppablePosition=useCallback(()=>{runOnUI(()=>{"worklet";const measurement=measure(animatedViewRef);if(measurement===null){return}if(measurement.width>0&&measurement.height>0){runOnJS(registerWithMeasurement)(measurement.pageX,measurement.pageY,measurement.width,measurement.height)}})()},[animatedViewRef,registerWithMeasurement]);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,2 +1,2 @@
|
|
|
1
|
-
import { UseHorizontalSortableOptions, UseHorizontalSortableReturn } from "../types/sortable";
|
|
2
|
-
export declare function useHorizontalSortable<T>(options: UseHorizontalSortableOptions<T>): UseHorizontalSortableReturn;
|
|
1
|
+
import { UseHorizontalSortableOptions, UseHorizontalSortableReturn } from "../types/sortable";
|
|
2
|
+
export declare function useHorizontalSortable<T>(options: UseHorizontalSortableOptions<T>): UseHorizontalSortableReturn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useState,useRef,useEffect,useMemo}from"react";import React from"react";import{runOnJS,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";import{setHorizontalPosition,setHorizontalAutoScroll,getItemXPosition,getContentWidth}from"../components/sortableUtils";import{HorizontalScrollDirection}from"../types/sortable";export function useHorizontalSortable(options){const{id,positions,leftBound,autoScrollDirection,itemsCount,itemWidth,gap=0,paddingHorizontal=0,containerWidth=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 initialLeftVal=useMemo((
|
|
1
|
+
import{useState,useRef,useEffect,useMemo}from"react";import React from"react";import{runOnJS,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";import{setHorizontalPosition,setHorizontalAutoScroll,getItemXPosition,getContentWidth}from"../components/sortableUtils";import{HorizontalScrollDirection}from"../types/sortable";export function useHorizontalSortable(options){const{id,positions,leftBound,autoScrollDirection,itemsCount,itemWidth,gap=0,paddingHorizontal=0,containerWidth=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 initialLeftVal=useMemo(()=>{const posArr=positions.get();const pos=posArr===null||posArr===void 0?void 0:posArr[id];return getItemXPosition(pos,itemWidth,gap,paddingHorizontal)},[]);const initialLeftBoundVal=useMemo(()=>leftBound.get(),[]);const positionX=useSharedValue(initialLeftVal);const left=useSharedValue(initialLeftVal);const targetLeftBound=useSharedValue(initialLeftBoundVal);const calculatedContainerWidth=useRef(containerWidth).current;const rightBound=useDerivedValue(()=>leftBound.value+calculatedContainerWidth);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(()=>positionX.value,(currentX,previousX)=>{if(currentX===null||!movingSV.value){return}if(previousX!==null&¤tX===previousX){return}const adjustedX=currentX-paddingHorizontal;const itemWithGapWidth=itemWidth+gap;const clampedPosition=Math.min(Math.max(0,Math.ceil(adjustedX/itemWithGapWidth)),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(currentX));onDraggingLastCallTimestamp.value=now}}left.value=currentX;setHorizontalPosition(currentX,itemsCount,positions,id,itemWidth,gap,paddingHorizontal);setHorizontalAutoScroll(currentX,leftBound.value,rightBound.value,itemWidth,autoScrollDirection)},[movingSV,itemWidth,gap,paddingHorizontal,itemsCount,positions,id,onDragging,leftBound,rightBound,autoScrollDirection,currentOverItemId,left,onDraggingLastCallTimestamp]);useAnimatedReaction(()=>positions.value[id],(currentPosition,previousPosition)=>{if(currentPosition!==null&&previousPosition!==null&¤tPosition!==previousPosition){if(!movingSV.value){const newLeft=getItemXPosition(currentPosition,itemWidth,gap,paddingHorizontal);left.value=withSpring(newLeft);if(onMove){runOnJS(onMove)(id,previousPosition,currentPosition)}}}},[movingSV,itemWidth,gap,paddingHorizontal]);useAnimatedReaction(()=>autoScrollDirection.value,(scrollDirection,previousValue)=>{if(scrollDirection!==null&&previousValue!==null&&scrollDirection!==previousValue){switch(scrollDirection){case HorizontalScrollDirection.Left:{targetLeftBound.value=leftBound.value;targetLeftBound.value=withTiming(0,{duration:1500});break}case HorizontalScrollDirection.Right:{const contentWidth=getContentWidth(itemsCount,itemWidth,gap,paddingHorizontal);const maxScroll=Math.max(0,contentWidth-calculatedContainerWidth);targetLeftBound.value=leftBound.value;targetLeftBound.value=withTiming(maxScroll,{duration:1500});break}case HorizontalScrollDirection.None:{targetLeftBound.value=leftBound.value;break}}}});useAnimatedReaction(()=>targetLeftBound.value,(targetLeftBoundValue,previousValue)=>{if(targetLeftBoundValue!==null&&previousValue!==null&&targetLeftBoundValue!==previousValue){if(movingSV.value){leftBound.value=targetLeftBoundValue}}},[movingSV]);const initialItemContentX=useSharedValue(0);const initialFingerAbsoluteX=useSharedValue(0);const initialLeftBound=useSharedValue(0);const panGestureHandler=Gesture.Pan().activateAfterLongPress(200).onStart(event=>{"worklet";initialItemContentX.value=getItemXPosition(positions.value[id],itemWidth,gap,paddingHorizontal);initialFingerAbsoluteX.value=event.absoluteX;initialLeftBound.value=leftBound.value;positionX.value=initialItemContentX.value;movingSV.value=true;runOnJS(setIsMoving)(true);if(onDragStart){runOnJS(onDragStart)(id,positions.value[id])}}).onUpdate(event=>{"worklet";const fingerDxScreen=event.absoluteX-initialFingerAbsoluteX.value;const scrollDeltaSinceStart=leftBound.value-initialLeftBound.value;positionX.value=initialItemContentX.value+fingerDxScreen+scrollDeltaSinceStart}).onEnd(()=>{"worklet";const finishPosition=getItemXPosition(positions.value[id],itemWidth,gap,paddingHorizontal);left.value=withTiming(finishPosition);movingSV.value=false;runOnJS(setIsMoving)(false);if(onDrop){const positionsCopy={...positions.value};runOnJS(onDrop)(id,positions.value[id],positionsCopy)}currentOverItemId.value=null});const animatedStyle=useAnimatedStyle(()=>{"worklet";return{position:"absolute",top:0,bottom:0,left:left.value,width:itemWidth,zIndex:movingSV.value?1:0,backgroundColor:"transparent",shadowColor:"black",shadowOpacity:withSpring(movingSV.value?.2:0),shadowRadius:10}},[movingSV,itemWidth]);return{animatedStyle,panGestureHandler,isMoving,hasHandle}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UseHorizontalSortableListOptions, UseHorizontalSortableListReturn } from "../types/sortable";
|
|
2
|
-
export declare function useHorizontalSortableList<TData extends {
|
|
3
|
-
id: string;
|
|
4
|
-
}>(options: UseHorizontalSortableListOptions<TData>): UseHorizontalSortableListReturn<TData>;
|
|
1
|
+
import { UseHorizontalSortableListOptions, UseHorizontalSortableListReturn } from "../types/sortable";
|
|
2
|
+
export declare function useHorizontalSortableList<TData extends {
|
|
3
|
+
id: string;
|
|
4
|
+
}>(options: UseHorizontalSortableListOptions<TData>): UseHorizontalSortableListReturn<TData>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useRef,useCallback}from"react";import{scrollTo,useAnimatedReaction,useAnimatedRef,useAnimatedScrollHandler,useSharedValue}from"react-native-reanimated";import{listToObject,getContentWidth}from"../components/sortableUtils";import{HorizontalScrollDirection}from"../types/sortable";export function useHorizontalSortableList(options){const{data,itemWidth,gap=0,paddingHorizontal=0,itemKeyExtractor=item=>item.id}=options;if(__DEV__){data.forEach((
|
|
1
|
+
import{useRef,useCallback}from"react";import{scrollTo,useAnimatedReaction,useAnimatedRef,useAnimatedScrollHandler,useSharedValue}from"react-native-reanimated";import{listToObject,getContentWidth}from"../components/sortableUtils";import{HorizontalScrollDirection}from"../types/sortable";export function useHorizontalSortableList(options){const{data,itemWidth,gap=0,paddingHorizontal=0,itemKeyExtractor=item=>item.id}=options;if(__DEV__){data.forEach((item,index)=>{const id=itemKeyExtractor(item,index);if(typeof id!=="string"||!id){console.error(`[react-native-reanimated-dnd] Item at index ${index} has invalid id: ${id}. `+`Each item must have a unique string id property.`)}})}const positions=useSharedValue(listToObject(data));const scrollX=useSharedValue(0);const autoScroll=useSharedValue(HorizontalScrollDirection.None);const scrollViewRef=useAnimatedRef();const dropProviderRef=useRef(null);useAnimatedReaction(()=>scrollX.value,scrolling=>{scrollTo(scrollViewRef,scrolling,0,false)});const handleScroll=useAnimatedScrollHandler(event=>{scrollX.value=event.contentOffset.x});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 contentWidth=getContentWidth(data.length,itemWidth,gap,paddingHorizontal);const getItemProps=useCallback((item,index)=>{const id=itemKeyExtractor(item,index);return{id,positions,leftBound:scrollX,autoScrollDirection:autoScroll,itemsCount:data.length,itemWidth,gap,paddingHorizontal}},[data.length,itemWidth,gap,paddingHorizontal,itemKeyExtractor,positions,scrollX,autoScroll]);return{positions,scrollX,autoScroll,scrollViewRef,dropProviderRef,handleScroll,handleScrollEnd,contentWidth,getItemProps}}
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { StyleProp, ViewStyle } from "react-native";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { SharedValue } from "react-native-reanimated";
|
|
4
|
-
import { GestureType } from "react-native-gesture-handler";
|
|
5
|
-
export declare enum ScrollDirection {
|
|
6
|
-
None = "none",
|
|
7
|
-
Up = "up",
|
|
8
|
-
Down = "down"
|
|
9
|
-
}
|
|
10
|
-
export declare function clamp(value: number, lowerBound: number, upperBound: number): number;
|
|
11
|
-
export declare function objectMove(object: {
|
|
12
|
-
[id: string]: number;
|
|
13
|
-
}, from: number, to: number): {
|
|
14
|
-
[id: string]: number;
|
|
15
|
-
};
|
|
16
|
-
export declare function listToObject<T extends {
|
|
17
|
-
id: string;
|
|
18
|
-
}>(list: T[]): {
|
|
19
|
-
[id: string]: number;
|
|
20
|
-
};
|
|
21
|
-
export declare function setPosition(positionY: number, itemsCount: number, positions: SharedValue<{
|
|
22
|
-
[id: string]: number;
|
|
23
|
-
}>, id: string, itemHeight: number): void;
|
|
24
|
-
export declare function setAutoScroll(positionY: number, lowerBound: number, upperBound: number, scrollThreshold: number, autoScroll: SharedValue<ScrollDirection>): void;
|
|
25
|
-
export interface UseSortableOptions<T> {
|
|
26
|
-
id: string;
|
|
27
|
-
positions: SharedValue<{
|
|
28
|
-
[id: string]: number;
|
|
29
|
-
}>;
|
|
30
|
-
lowerBound: SharedValue<number>;
|
|
31
|
-
autoScrollDirection: SharedValue<ScrollDirection>;
|
|
32
|
-
itemsCount: number;
|
|
33
|
-
itemHeight: number;
|
|
34
|
-
containerHeight?: number;
|
|
35
|
-
onMove?: (id: string, from: number, to: number) => void;
|
|
36
|
-
onDragStart?: (id: string, position: number) => void;
|
|
37
|
-
onDrop?: (id: string, position: number, allPositions?: {
|
|
38
|
-
[id: string]: number;
|
|
39
|
-
}) => void;
|
|
40
|
-
onDragging?: (id: string, overItemId: string | null, yPosition: number) => void;
|
|
41
|
-
children?: React.ReactNode;
|
|
42
|
-
handleComponent?: React.ComponentType<any>;
|
|
43
|
-
}
|
|
44
|
-
export interface UseSortableReturn {
|
|
45
|
-
animatedStyle: StyleProp<ViewStyle>;
|
|
46
|
-
panGestureHandler: GestureType;
|
|
47
|
-
isMoving: boolean;
|
|
48
|
-
hasHandle: boolean;
|
|
49
|
-
}
|
|
50
|
-
export declare function useSortable<T>(options: UseSortableOptions<T>): UseSortableReturn;
|
|
1
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { SharedValue } from "react-native-reanimated";
|
|
4
|
+
import { GestureType } from "react-native-gesture-handler";
|
|
5
|
+
export declare enum ScrollDirection {
|
|
6
|
+
None = "none",
|
|
7
|
+
Up = "up",
|
|
8
|
+
Down = "down"
|
|
9
|
+
}
|
|
10
|
+
export declare function clamp(value: number, lowerBound: number, upperBound: number): number;
|
|
11
|
+
export declare function objectMove(object: {
|
|
12
|
+
[id: string]: number;
|
|
13
|
+
}, from: number, to: number): {
|
|
14
|
+
[id: string]: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function listToObject<T extends {
|
|
17
|
+
id: string;
|
|
18
|
+
}>(list: T[]): {
|
|
19
|
+
[id: string]: number;
|
|
20
|
+
};
|
|
21
|
+
export declare function setPosition(positionY: number, itemsCount: number, positions: SharedValue<{
|
|
22
|
+
[id: string]: number;
|
|
23
|
+
}>, id: string, itemHeight: number): void;
|
|
24
|
+
export declare function setAutoScroll(positionY: number, lowerBound: number, upperBound: number, scrollThreshold: number, autoScroll: SharedValue<ScrollDirection>): void;
|
|
25
|
+
export interface UseSortableOptions<T> {
|
|
26
|
+
id: string;
|
|
27
|
+
positions: SharedValue<{
|
|
28
|
+
[id: string]: number;
|
|
29
|
+
}>;
|
|
30
|
+
lowerBound: SharedValue<number>;
|
|
31
|
+
autoScrollDirection: SharedValue<ScrollDirection>;
|
|
32
|
+
itemsCount: number;
|
|
33
|
+
itemHeight: number;
|
|
34
|
+
containerHeight?: number;
|
|
35
|
+
onMove?: (id: string, from: number, to: number) => void;
|
|
36
|
+
onDragStart?: (id: string, position: number) => void;
|
|
37
|
+
onDrop?: (id: string, position: number, allPositions?: {
|
|
38
|
+
[id: string]: number;
|
|
39
|
+
}) => void;
|
|
40
|
+
onDragging?: (id: string, overItemId: string | null, yPosition: number) => void;
|
|
41
|
+
children?: React.ReactNode;
|
|
42
|
+
handleComponent?: React.ComponentType<any>;
|
|
43
|
+
}
|
|
44
|
+
export interface UseSortableReturn {
|
|
45
|
+
animatedStyle: StyleProp<ViewStyle>;
|
|
46
|
+
panGestureHandler: GestureType;
|
|
47
|
+
isMoving: boolean;
|
|
48
|
+
hasHandle: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function useSortable<T>(options: UseSortableOptions<T>): UseSortableReturn;
|
package/lib/hooks/useSortable.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useState,useRef,useEffect,useMemo}from"react";import React from"react";import{runOnJS,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";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);const movedUp=to<from;for(const id in object){if(object[id]===from){newObject[id]=to;continue}const currentPosition=object[id];if(movedUp&¤tPosition>=to&¤tPosition<from){newObject[id]++}else if(currentPosition<=to&¤tPosition>from){newObject[id]--}}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 initialTopVal=useMemo((
|
|
1
|
+
import{useState,useRef,useEffect,useMemo}from"react";import React from"react";import{runOnJS,useAnimatedReaction,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,withTiming}from"react-native-reanimated";import{Gesture}from"react-native-gesture-handler";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);const movedUp=to<from;for(const id in object){if(object[id]===from){newObject[id]=to;continue}const currentPosition=object[id];if(movedUp&¤tPosition>=to&¤tPosition<from){newObject[id]++}else if(currentPosition<=to&¤tPosition>from){newObject[id]--}}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 initialTopVal=useMemo(()=>{const posArr=positions.get();const pos=posArr===null||posArr===void 0?void 0:posArr[id];return pos*itemHeight},[]);const initialLowerBoundVal=useMemo(()=>lowerBound.get(),[]);const positionY=useSharedValue(initialTopVal);const top=useSharedValue(initialTopVal);const targetLowerBound=useSharedValue(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}const props=child.props;if(child.props&&props.children){if(React.Children.toArray(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&¤tY===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&¤tPosition!==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 initialItemContentY=useSharedValue(0);const initialFingerAbsoluteY=useSharedValue(0);const initialLowerBound=useSharedValue(0);const panGestureHandler=Gesture.Pan().activateAfterLongPress(200).onStart(event=>{"worklet";initialItemContentY.value=positions.value[id]*itemHeight;initialFingerAbsoluteY.value=event.absoluteY;initialLowerBound.value=lowerBound.value;positionY.value=initialItemContentY.value;movingSV.value=true;runOnJS(setIsMoving)(true);if(onDragStart){runOnJS(onDragStart)(id,positions.value[id])}}).onUpdate(event=>{"worklet";const fingerDyScreen=event.absoluteY-initialFingerAbsoluteY.value;const scrollDeltaSinceStart=lowerBound.value-initialLowerBound.value;positionY.value=initialItemContentY.value+fingerDyScreen+scrollDeltaSinceStart}).onEnd(()=>{"worklet";const finishPosition=positions.value[id]*itemHeight;top.value=withTiming(finishPosition);movingSV.value=false;runOnJS(setIsMoving)(false);if(onDrop){const positionsCopy={...positions.value};runOnJS(onDrop)(id,positions.value[id],positionsCopy)}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,27 +1,27 @@
|
|
|
1
|
-
import { DropProviderRef } from "../types/context";
|
|
2
|
-
export interface UseSortableListOptions<TData> {
|
|
3
|
-
data: TData[];
|
|
4
|
-
itemHeight: number;
|
|
5
|
-
itemKeyExtractor?: (item: TData, index: number) => string;
|
|
6
|
-
}
|
|
7
|
-
export interface UseSortableListReturn<TData> {
|
|
8
|
-
positions: any;
|
|
9
|
-
scrollY: any;
|
|
10
|
-
autoScroll: any;
|
|
11
|
-
scrollViewRef: any;
|
|
12
|
-
dropProviderRef: React.RefObject<DropProviderRef>;
|
|
13
|
-
handleScroll: any;
|
|
14
|
-
handleScrollEnd: () => void;
|
|
15
|
-
contentHeight: number;
|
|
16
|
-
getItemProps: (item: TData, index: number) => {
|
|
17
|
-
id: string;
|
|
18
|
-
positions: any;
|
|
19
|
-
lowerBound: any;
|
|
20
|
-
autoScrollDirection: any;
|
|
21
|
-
itemsCount: number;
|
|
22
|
-
itemHeight: number;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export declare function useSortableList<TData extends {
|
|
26
|
-
id: string;
|
|
27
|
-
}>(options: UseSortableListOptions<TData>): UseSortableListReturn<TData>;
|
|
1
|
+
import { DropProviderRef } from "../types/context";
|
|
2
|
+
export interface UseSortableListOptions<TData> {
|
|
3
|
+
data: TData[];
|
|
4
|
+
itemHeight: number;
|
|
5
|
+
itemKeyExtractor?: (item: TData, index: number) => string;
|
|
6
|
+
}
|
|
7
|
+
export interface UseSortableListReturn<TData> {
|
|
8
|
+
positions: any;
|
|
9
|
+
scrollY: any;
|
|
10
|
+
autoScroll: any;
|
|
11
|
+
scrollViewRef: any;
|
|
12
|
+
dropProviderRef: React.RefObject<DropProviderRef>;
|
|
13
|
+
handleScroll: any;
|
|
14
|
+
handleScrollEnd: () => void;
|
|
15
|
+
contentHeight: number;
|
|
16
|
+
getItemProps: (item: TData, index: number) => {
|
|
17
|
+
id: string;
|
|
18
|
+
positions: any;
|
|
19
|
+
lowerBound: any;
|
|
20
|
+
autoScrollDirection: any;
|
|
21
|
+
itemsCount: number;
|
|
22
|
+
itemHeight: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function useSortableList<TData extends {
|
|
26
|
+
id: string;
|
|
27
|
+
}>(options: UseSortableListOptions<TData>): UseSortableListReturn<TData>;
|
|
@@ -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(options){const{data,itemHeight,itemKeyExtractor=item=>item.id}=options;if(__DEV__){data.forEach((
|
|
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;if(__DEV__){data.forEach((item,index)=>{const id=itemKeyExtractor(item,index);if(typeof id!=="string"||!id){console.error(`[react-native-reanimated-dnd] Item at index ${index} has invalid id: ${id}. `+`Each item must have a unique string id property.`)}})}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}}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { Draggable } from "./components/Draggable";
|
|
2
|
-
export { Droppable } from "./components/Droppable";
|
|
3
|
-
export { Sortable } from "./components/Sortable";
|
|
4
|
-
export { SortableItem } from "./components/SortableItem";
|
|
5
|
-
export { DropProvider } from "./context/DropContext";
|
|
6
|
-
export * from "./types";
|
|
7
|
-
export { listToObject, setAutoScroll, setPosition, clamp, objectMove, ScrollDirection, } from "./components/sortableUtils";
|
|
8
|
-
export { useDraggable } from "./hooks/useDraggable";
|
|
9
|
-
export { useDroppable } from "./hooks/useDroppable";
|
|
10
|
-
export { useSortable } from "./hooks/useSortable";
|
|
11
|
-
export { useSortableList } from "./hooks/useSortableList";
|
|
12
|
-
export { useHorizontalSortable } from "./hooks/useHorizontalSortable";
|
|
13
|
-
export { useHorizontalSortableList } from "./hooks/useHorizontalSortableList";
|
|
1
|
+
export { Draggable } from "./components/Draggable";
|
|
2
|
+
export { Droppable } from "./components/Droppable";
|
|
3
|
+
export { Sortable } from "./components/Sortable";
|
|
4
|
+
export { SortableItem } from "./components/SortableItem";
|
|
5
|
+
export { DropProvider } from "./context/DropContext";
|
|
6
|
+
export * from "./types";
|
|
7
|
+
export { listToObject, setAutoScroll, setPosition, clamp, objectMove, ScrollDirection, } from "./components/sortableUtils";
|
|
8
|
+
export { useDraggable } from "./hooks/useDraggable";
|
|
9
|
+
export { useDroppable } from "./hooks/useDroppable";
|
|
10
|
+
export { useSortable } from "./hooks/useSortable";
|
|
11
|
+
export { useSortableList } from "./hooks/useSortableList";
|
|
12
|
+
export { useHorizontalSortable } from "./hooks/useHorizontalSortable";
|
|
13
|
+
export { useHorizontalSortableList } from "./hooks/useHorizontalSortableList";
|