UNPKG

react-native-sortables

Version:

Powerful Sortable Components for Flexible Content Reordering in React Native

142 lines (134 loc) 5.43 kB
"use strict"; import { useCallback } from 'react'; import { measure, runOnUI, useAnimatedReaction, useAnimatedRef, useSharedValue } from 'react-native-reanimated'; import { OFFSET_EPS } from '../../constants'; import { useUIStableCallback } from '../../hooks'; import { areDimensionsDifferent, useAnimatedDebounce } from '../../utils'; import { createProvider } from '../utils'; import { useCommonValuesContext } from './CommonValuesProvider'; const { MeasurementsProvider, useMeasurementsContext } = createProvider('Measurements')(({ itemsCount }) => { const { activeItemDimensions, activeItemKey, containerHeight, containerWidth, controlledContainerDimensions, itemDimensions, measuredContainerHeight, measuredContainerWidth, usesAbsoluteLayout } = useCommonValuesContext(); const measurementsContainerRef = useAnimatedRef(); const measuredItemsCount = useSharedValue(0); const initialItemMeasurementsCompleted = useSharedValue(false); const debounce = useAnimatedDebounce(); const handleItemMeasurement = useUIStableCallback((key, dimensions) => { 'worklet'; const storedDimensions = itemDimensions.value[key]; if (storedDimensions && !areDimensionsDifferent(storedDimensions, dimensions, 1)) { return; } if (!itemDimensions.value[key]) { measuredItemsCount.value += 1; } itemDimensions.value[key] = dimensions; if (activeItemKey.value === key) { activeItemDimensions.value = dimensions; } // Update the array of item dimensions only after all items have been // measured to reduce the number of times animated reactions are triggered if (measuredItemsCount.value === itemsCount) { // If this is the first time all items have been measured, update // dimensions immediately to avoid unnecessary delays if (!initialItemMeasurementsCompleted.value) { initialItemMeasurementsCompleted.value = true; itemDimensions.modify(); } else if (usesAbsoluteLayout.value) { // In all other cases, debounce the update in case multiple items // change their size at the same time debounce(itemDimensions.modify, 100); } } }); const removeItemMeasurements = useUIStableCallback(key => { 'worklet'; delete itemDimensions.value[key]; measuredItemsCount.value = Math.max(0, measuredItemsCount.value - 1); }); const applyControlledContainerDimensions = useCallback(dimensions => { 'worklet'; // Reset container dimensions to the measured dimensions containerHeight.value = measuredContainerHeight.value ?? null; containerWidth.value = measuredContainerWidth.value ?? null; // Override controlled dimensions (dimensions that are applied based // on the sortable component layout calculations) if (controlledContainerDimensions.value.height && dimensions.height !== undefined) { containerHeight.value = dimensions.height; } if (controlledContainerDimensions.value.width && dimensions.width !== undefined) { containerWidth.value = dimensions.width; } }, [containerHeight, containerWidth, controlledContainerDimensions, measuredContainerHeight, measuredContainerWidth]); const applyMeasuredContainerDimensions = useCallback(dimensions => { 'worklet'; measuredContainerHeight.value = dimensions.height; measuredContainerWidth.value = dimensions.width; if (usesAbsoluteLayout.value) { if (!controlledContainerDimensions.value.height) { containerHeight.value = dimensions.height; } if (!controlledContainerDimensions.value.width) { containerWidth.value = dimensions.width; } } }, [usesAbsoluteLayout, containerHeight, containerWidth, controlledContainerDimensions, measuredContainerHeight, measuredContainerWidth]); const handleHelperContainerMeasurement = useCallback(({ nativeEvent: { layout } }) => { runOnUI(applyMeasuredContainerDimensions)(layout); }, [applyMeasuredContainerDimensions]); const measureContainer = useCallback(() => { 'worklet'; const measurements = measure(measurementsContainerRef); if (measurements) { applyMeasuredContainerDimensions(measurements); } }, [applyMeasuredContainerDimensions, measurementsContainerRef]); useAnimatedReaction(() => ({ containerH: containerHeight.value, containerW: containerWidth.value, itemMeasurementsCompleted: initialItemMeasurementsCompleted.value, measuredHeight: measuredContainerHeight.value, measuredWidth: measuredContainerWidth.value }), ({ containerH, containerW, itemMeasurementsCompleted, measuredHeight, measuredWidth }) => { if (usesAbsoluteLayout.value || !itemMeasurementsCompleted || measuredHeight === null || measuredWidth === null || containerH === null && containerW === null || containerH !== null && Math.abs(measuredHeight - containerH) > OFFSET_EPS || containerW !== null && Math.abs(measuredWidth - containerW) > OFFSET_EPS) { return; } usesAbsoluteLayout.value = true; }); return { value: { applyControlledContainerDimensions, handleHelperContainerMeasurement, handleItemMeasurement, measureContainer, measurementsContainerRef, removeItemMeasurements } }; }); export { MeasurementsProvider, useMeasurementsContext }; //# sourceMappingURL=MeasurementsProvider.js.map