UNPKG

react-native-sortables

Version:

Powerful Sortable Components for Flexible Content Reordering in React Native

166 lines (158 loc) 5.03 kB
"use strict"; import { useCallback } from 'react'; import { useAnimatedReaction, useDerivedValue, useSharedValue } from 'react-native-reanimated'; import { IS_WEB } from '../../../constants'; import { useDebugContext } from '../../../debug'; import { useAnimatableValue } from '../../../hooks'; import { useCommonValuesContext, useMeasurementsContext } from '../../shared'; import { createProvider } from '../../utils'; import { calculateLayout } from './utils'; const DEBUG_COLORS = { backgroundColor: '#ffa500', borderColor: '#825500' }; const { GridLayoutProvider, useGridLayoutContext } = createProvider('GridLayout')(({ columnGap: columnGap_, isVertical, numGroups, numItems, rowGap: rowGap_, rowHeight }) => { const { indexToKey, itemDimensions, itemPositions, itemsStyleOverride, measuredContainerWidth, shouldAnimateLayout } = useCommonValuesContext(); const { applyControlledContainerDimensions } = useMeasurementsContext(); const debugContext = useDebugContext(); const debugMainGapRects = debugContext?.useDebugRects(numGroups - 1); const debugCrossGapRects = debugContext?.useDebugRects(Math.ceil(numItems / numGroups) - 1); const columnGap = useAnimatableValue(columnGap_); const rowGap = useAnimatableValue(rowGap_); const mainGap = isVertical ? columnGap : rowGap; const crossGap = isVertical ? rowGap : columnGap; /** * Size of the group of items determined by the parent container size. * width - in vertical orientation (default) (columns are groups) * height - in horizontal orientation (rows are groups) */ const mainGroupSize = useSharedValue(rowHeight ?? null); // MAIN GROUP SIZE UPDATER useAnimatedReaction(() => { if (!isVertical) { return rowHeight ?? null; } const mainContainerWidth = measuredContainerWidth.value; if (!mainContainerWidth) { return null; } return (mainContainerWidth + mainGap.value) / numGroups - mainGap.value; }, value => { if (!value) { return; } mainGroupSize.value = value; // DEBUG ONLY if (debugMainGapRects) { const gap = mainGap.value; for (let i = 0; i < numGroups - 1; i++) { const size = value * (i + 1) + gap * i; debugMainGapRects[i]?.set({ ...DEBUG_COLORS, ...(isVertical ? { width: gap, x: size } : { height: gap, y: size }) }); } } }); const useGridLayoutReaction = useCallback((idxToKey, onChange) => useAnimatedReaction(() => ({ gaps: { cross: crossGap.value, main: mainGap.value }, indexToKey: idxToKey.value, isVertical, itemDimensions: itemDimensions.value, mainGroupSize: mainGroupSize.value, numGroups }), (props, previousProps) => { onChange(calculateLayout(props), // On web, animate layout only if parent container is not resized // (e.g. skip animation when the browser window is resized) !IS_WEB || !previousProps?.mainGroupSize || props.mainGroupSize === previousProps.mainGroupSize); }), [mainGroupSize, mainGap, crossGap, numGroups, isVertical, itemDimensions]); const useGridLayout = useCallback(idxToKey => useDerivedValue(() => calculateLayout({ gaps: { cross: crossGap.value, main: mainGap.value }, indexToKey: idxToKey.value, isVertical, itemDimensions: itemDimensions.value, mainGroupSize: mainGroupSize.value, numGroups })), [mainGroupSize, mainGap, crossGap, numGroups, isVertical, itemDimensions]); // GRID LAYOUT UPDATER useGridLayoutReaction(indexToKey, (layout, shouldAnimate) => { 'worklet'; shouldAnimateLayout.value = shouldAnimate; if (!layout || mainGroupSize.value === null) { return; } // Update item positions itemPositions.value = layout.itemPositions; // Update controlled container dimensions applyControlledContainerDimensions(layout.calculatedDimensions); // Update style overrides const currentStyleOverride = itemsStyleOverride.value; const mainDimension = isVertical ? 'width' : 'height'; if (currentStyleOverride?.[mainDimension] !== mainGroupSize.value) { itemsStyleOverride.value = { [mainDimension]: mainGroupSize.value }; } // DEBUG ONLY if (debugCrossGapRects) { for (let i = 0; i < layout.crossAxisOffsets.length - 1; i++) { const size = crossGap.value; const pos = layout.crossAxisOffsets[i + 1] - crossGap.value; debugCrossGapRects[i]?.set({ ...DEBUG_COLORS, ...(isVertical ? { height: size, y: pos } : { width: size, x: pos }) }); } } }); return { value: { crossGap, isVertical, mainGap, mainGroupSize, numGroups, useGridLayout } }; }); export { GridLayoutProvider, useGridLayoutContext }; //# sourceMappingURL=GridLayoutProvider.js.map