UNPKG

react-native-reorderable-list

Version:

Reorderable list for React Native applications, powered by Reanimated

98 lines (97 loc) 3.57 kB
import React, { memo, useCallback, useMemo } from 'react'; import Animated, { Easing, runOnUI, useAnimatedReaction, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'; import { ReorderableCellContext, ReorderableListContext } from '../contexts'; import { useContext } from '../hooks'; import { applyAnimatedStyles } from './helpers'; export const ReorderableListCell = /*#__PURE__*/memo(({ index, startDrag, children, onLayout, itemOffset, itemHeight, dragY, draggedIndex, animationDuration }) => { const { currentIndex, draggedHeight, activeIndex, cellAnimations, itemLayoutAnimation } = useContext(ReorderableListContext); const dragHandler = useCallback(() => runOnUI(startDrag)(index), [startDrag, index]); const isActive = activeIndex === index; const contextValue = useMemo(() => ({ index, dragHandler, draggedIndex, isActive }), [index, dragHandler, draggedIndex, isActive]); // Keep separate animated reactions that update itemTranslateY // otherwise animations might stutter if multiple are triggered // (even in other cells, e.g. released item and reordering cells) const itemTranslateY = useSharedValue(0); const isActiveCell = useDerivedValue(() => draggedIndex.value === index); useAnimatedReaction(() => dragY.value, () => { if (index === draggedIndex.value && currentIndex.value >= 0 && draggedIndex.value >= 0) { itemTranslateY.value = dragY.value; } }); useAnimatedReaction(() => currentIndex.value, () => { if (index !== draggedIndex.value && currentIndex.value >= 0 && draggedIndex.value >= 0) { const moveUp = currentIndex.value > draggedIndex.value; const startMove = Math.min(draggedIndex.value, currentIndex.value); const endMove = Math.max(draggedIndex.value, currentIndex.value); let newValue = 0; if (index >= startMove && index <= endMove) { newValue = moveUp ? -draggedHeight.value : draggedHeight.value; } if (newValue !== itemTranslateY.value) { itemTranslateY.value = withTiming(newValue, { duration: animationDuration.value, easing: Easing.out(Easing.ease) }); } } }); const animatedStyle = useAnimatedStyle(() => { if (isActiveCell.value) { const transform = [{ translateY: itemTranslateY.value }]; if (Array.isArray(cellAnimations.transform)) { const customTransform = cellAnimations.transform.map(x => applyAnimatedStyles({}, x)); transform.push(...customTransform); } return applyAnimatedStyles({ transform, zIndex: 999 }, cellAnimations, ['transform']); } return { transform: [{ translateY: itemTranslateY.value }], // TODO: move to stylesheet when this is fixed // https://github.com/software-mansion/react-native-reanimated/issues/6681#issuecomment-2514228447 zIndex: 0 }; }); const handleLayout = e => { runOnUI((y, height) => { itemOffset.value[index] = y; itemHeight.value[index] = height; })(e.nativeEvent.layout.y, e.nativeEvent.layout.height); onLayout === null || onLayout === void 0 || onLayout(e); }; return /*#__PURE__*/React.createElement(ReorderableCellContext.Provider, { value: contextValue }, /*#__PURE__*/React.createElement(Animated.View, { style: animatedStyle, onLayout: handleLayout, layout: itemLayoutAnimation.current }, children)); }); //# sourceMappingURL=ReorderableListCell.js.map