UNPKG

react-native-sortables

Version:

Powerful Sortable Components for Flexible Content Reordering in React Native

103 lines (99 loc) 3.82 kB
"use strict"; import { useCallback } from 'react'; import { runOnJS, scrollTo, useAnimatedReaction, useDerivedValue, useFrameCallback, useScrollViewOffset } from 'react-native-reanimated'; import { OFFSET_EPS } from '../../../constants'; import { useAnimatableValue, useMutableValue } from '../../../integrations/reanimated'; import { createProvider } from '../../utils'; import { useCommonValuesContext } from '../CommonValuesProvider'; import useTargetScrollOffset from './useTargetScrollOffset'; const { AutoScrollProvider, useAutoScrollContext } = createProvider('AutoScroll', { guarded: false })(({ autoScrollActivationOffset, autoScrollDirection, autoScrollEnabled, autoScrollSpeed, maxScrollToOverflowOffset, scrollableRef }) => { const isHorizontal = autoScrollDirection === 'horizontal'; const { activeItemKey } = useCommonValuesContext(); const scrollOffset = useScrollViewOffset(scrollableRef); const dragStartScrollOffset = useAnimatableValue(null); const prevScrollToOffset = useMutableValue(null); const scrollOffsetDiff = useDerivedValue(() => { if (dragStartScrollOffset.value === null) { return null; } return { x: isHorizontal ? scrollOffset.value - dragStartScrollOffset.value : 0, y: isHorizontal ? 0 : scrollOffset.value - dragStartScrollOffset.value }; }); const enabled = useAnimatableValue(autoScrollEnabled); const speed = useAnimatableValue(autoScrollSpeed); const isFrameCallbackActive = useMutableValue(false); const targetScrollOffset = useTargetScrollOffset(scrollableRef, enabled, isHorizontal, autoScrollActivationOffset, maxScrollToOverflowOffset, dragStartScrollOffset); // SMOOTH SCROLL POSITION UPDATER // Updates the scroll position smoothly // (quickly at first, then slower if the remaining distance is small) const frameCallback = useFrameCallback(() => { const targetOffset = targetScrollOffset.value; if (!isFrameCallbackActive.value || targetOffset === null) { return; } const currentOffset = scrollOffset.value; const diff = targetOffset - currentOffset; if (Math.abs(diff) < OFFSET_EPS) { targetScrollOffset.value = null; return; } const direction = diff > 0 ? 1 : -1; const step = speed.value * direction * Math.sqrt(Math.abs(diff)); const nextOffset = targetOffset > currentOffset ? Math.min(currentOffset + step, targetOffset) : Math.max(currentOffset + step, targetOffset); if (Math.abs(nextOffset - currentOffset) < 0.1 * OFFSET_EPS || prevScrollToOffset.value === nextOffset) { targetScrollOffset.value = null; return; } if (isHorizontal) { scrollTo(scrollableRef, nextOffset, 0, false); } else { scrollTo(scrollableRef, 0, nextOffset, false); } prevScrollToOffset.value = nextOffset; }, false); const toggleFrameCallback = useCallback(isEnabled => frameCallback.setActive(isEnabled), [frameCallback]); // Enable/disable frame callback useAnimatedReaction(() => ({ isEnabled: enabled.value, itemKey: activeItemKey.value }), ({ isEnabled, itemKey }) => { const shouldBeEnabled = isEnabled && itemKey !== null; if (isFrameCallbackActive.value === shouldBeEnabled) { return; } prevScrollToOffset.value = null; runOnJS(toggleFrameCallback)(shouldBeEnabled); isFrameCallbackActive.value = shouldBeEnabled; }); const updateStartScrollOffset = useCallback(providedOffset => { 'worklet'; dragStartScrollOffset.value = providedOffset === undefined ? scrollOffset.value : providedOffset; }, [dragStartScrollOffset, scrollOffset]); return { value: { scrollOffsetDiff, updateStartScrollOffset } }; }); export { AutoScrollProvider, useAutoScrollContext }; //# sourceMappingURL=index.js.map