UNPKG

react-native-sortables

Version:

Powerful Sortable Components for Flexible Content Reordering in React Native

176 lines (170 loc) 5.78 kB
"use strict"; import { useCallback } from 'react'; import { useAnimatedReaction, useDerivedValue } from 'react-native-reanimated'; import { IS_WEB } from '../../../constants'; import { useDebugContext } from '../../../debug'; import { useMutableValue } from '../../../integrations/reanimated'; import { haveEqualPropValues } from '../../../utils'; import { useCommonValuesContext, useMeasurementsContext } from '../../shared'; import { createProvider } from '../../utils'; import { calculateLayout, updateLayoutDebugRects } from './utils'; const { FlexLayoutProvider, useFlexLayoutContext } = createProvider('FlexLayout')(({ alignContent, alignItems, columnGap: columnGap_, flexDirection, flexWrap, gap, height, itemsCount, justifyContent, maxHeight, maxWidth, minHeight, minWidth, padding, paddingBottom, paddingHorizontal, paddingLeft, paddingRight, paddingTop, paddingVertical, rowGap: rowGap_, width }) => { const { containerHeight, containerWidth, controlledContainerDimensions, indexToKey, itemHeights, itemPositions, itemWidths, shouldAnimateLayout } = useCommonValuesContext(); const { applyControlledContainerDimensions } = useMeasurementsContext(); const debugContext = useDebugContext(); const keyToGroup = useMutableValue({}); const columnGap = useDerivedValue(() => columnGap_ ?? gap); const rowGap = useDerivedValue(() => rowGap_ ?? gap); const paddings = useDerivedValue(() => ({ bottom: paddingBottom ?? paddingVertical ?? padding, left: paddingLeft ?? paddingHorizontal ?? padding, right: paddingRight ?? paddingHorizontal ?? padding, top: paddingTop ?? paddingVertical ?? padding })); const dimensionsLimits = useDerivedValue(() => { const h = height === 'fill' ? undefined : height; const w = width === 'fill' ? undefined : width; let minH = Math.max(minHeight ?? 0, h ?? 0); let maxH = Math.min(maxHeight ?? Infinity, h ?? Infinity); let minW = Math.max(minWidth ?? 0, w ?? 0); let maxW = Math.min(maxWidth ?? Infinity, w ?? Infinity); if (!controlledContainerDimensions.width) { if (!containerWidth.value) { return null; } minW = maxW = containerWidth.value; } if (!controlledContainerDimensions.height) { if (!containerHeight.value) { return null; } minH = maxH = containerHeight.value; } return { maxHeight: maxH, maxWidth: maxW, minHeight: maxHeight ? Math.min(minH, maxH) : minH, minWidth: maxWidth ? Math.min(minW, maxW) : minW }; }); const appliedLayout = useMutableValue(null); // Because the number of groups can dynamically change after order change // and we can't detect that in the React runtime, we are creating debug // rects for the maximum number of groups that can be displayed (which // is the number of items minus 1 in the worst case for just a single group) const debugCrossAxisGapRects = debugContext?.useDebugRects(itemsCount - 1); const debugMainAxisGapRects = debugContext?.useDebugRects(itemsCount); const useFlexLayoutReaction = useCallback((idxToKey, onChange) => useAnimatedReaction(() => idxToKey.value === null ? null : { flexAlignments: { alignContent, alignItems, justifyContent }, flexDirection, flexWrap, gaps: { column: columnGap.value, row: rowGap.value }, indexToKey: idxToKey.value, itemHeights: itemHeights.value, itemWidths: itemWidths.value, limits: dimensionsLimits.value, paddings: paddings.value }, (props, previousProps) => { onChange(props && 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?.limits || haveEqualPropValues(props?.limits, previousProps?.limits)); }), [alignContent, alignItems, justifyContent, flexDirection, flexWrap, columnGap, rowGap, itemHeights, itemWidths, dimensionsLimits, paddings]); const calculateFlexLayout = useCallback(idxToKey => { 'worklet'; return calculateLayout({ flexAlignments: { alignContent, alignItems, justifyContent }, flexDirection, flexWrap, gaps: { column: columnGap.value, row: rowGap.value }, indexToKey: idxToKey, itemHeights: itemHeights.value, itemWidths: itemWidths.value, limits: dimensionsLimits.value, paddings: paddings.value }); }, [alignContent, alignItems, justifyContent, flexDirection, flexWrap, columnGap, rowGap, itemHeights, itemWidths, dimensionsLimits, paddings]); useFlexLayoutReaction(indexToKey, (layout, shouldAnimate) => { 'worklet'; shouldAnimateLayout.value = shouldAnimate; if (!layout) { return; } // Update current layout appliedLayout.value = layout; // Update item positions itemPositions.value = layout.itemPositions; // Update controlled container dimensions applyControlledContainerDimensions(layout.totalDimensions); // Update key to group keyToGroup.value = Object.fromEntries(layout.itemGroups.flatMap((group, i) => group.map(key => [key, i]))); // DEBUG ONLY if (debugCrossAxisGapRects && debugMainAxisGapRects) { updateLayoutDebugRects(flexDirection, layout, debugCrossAxisGapRects, debugMainAxisGapRects, itemWidths.value, itemHeights.value); } }); return { value: { appliedLayout, calculateFlexLayout, columnGap, flexDirection, keyToGroup, rowGap, useFlexLayoutReaction } }; }); export { FlexLayoutProvider, useFlexLayoutContext }; //# sourceMappingURL=FlexLayoutProvider.js.map