react-native-sortables
Version:
Powerful Sortable Components for Flexible Content Reordering in React Native
74 lines (63 loc) • 2.22 kB
text/typescript
import type { View } from 'react-native';
import type { AnimatedRef, SharedValue } from 'react-native-reanimated';
import { measure, useAnimatedReaction } from 'react-native-reanimated';
import { useMutableValue } from '../../../../integrations/reanimated';
import useZoneContext from './useZoneContext';
export type ZoneHandlers = {
onItemEnter?: () => void;
onItemLeave?: () => void;
onItemDrop?: () => void;
};
export default function useZoneHandlers(
containerRef: AnimatedRef<View>,
minActivationDistance: number,
handlers?: ZoneHandlers
): SharedValue<boolean> {
const { activeItemAbsolutePosition, activeItemDimensions } = useZoneContext();
const isInZone = useMutableValue(false);
useAnimatedReaction(
() => ({
dimensions: activeItemDimensions.value,
offset: minActivationDistance,
position: activeItemAbsolutePosition.value
}),
({ dimensions, offset, position }, prev) => {
const hasActiveItem = !!position && !!dimensions;
if (!hasActiveItem) {
const hadActiveItem = !!prev?.dimensions && !!prev?.position;
if (isInZone.value && hadActiveItem) {
handlers?.onItemDrop?.();
}
isInZone.value = false;
return;
}
const container = measure(containerRef);
if (!container) {
isInZone.value = false;
return;
}
// TODO - maybe add a possibility to customize the item origin
const centerX = position.x + dimensions.width / 2;
const centerY = position.y + dimensions.height / 2;
const { height, pageX, pageY, width } = container;
// Check if the item is within the bounding box of the zone
const minX = pageX - offset;
const maxX = pageX + width + offset;
const minY = pageY - offset;
const maxY = pageY + height + offset;
const inZone =
centerX >= minX &&
centerX <= maxX &&
centerY >= minY &&
centerY <= maxY;
if (inZone && !isInZone.value) {
isInZone.value = true;
handlers?.onItemEnter?.();
} else if (!inZone && isInZone.value) {
isInZone.value = false;
handlers?.onItemLeave?.();
}
}
);
return isInZone;
}