react-native-sortables
Version:
Powerful Sortable Components for Flexible Content Reordering in React Native
223 lines (214 loc) • 7.41 kB
JavaScript
"use strict";
import { useDerivedValue } from 'react-native-reanimated';
import { getAdditionalSwapOffset, useCommonValuesContext, useCustomHandleContext, useDebugBoundingBox } from '../../../shared';
import { useAutoOffsetAdjustmentContext } from '../../AutoOffsetAdjustmentProvider';
import { useGridLayoutContext } from '../GridLayoutProvider';
import { calculateLayout, getCrossIndex, getMainIndex } from '../utils';
export const createGridStrategy = (useInactiveIndexToKey, reorder) => () => {
const {
containerHeight,
containerWidth,
indexToKey,
itemHeights,
itemWidths
} = useCommonValuesContext();
const {
crossGap,
isVertical,
mainGap,
mainGroupSize,
numGroups
} = useGridLayoutContext();
const {
additionalCrossOffset
} = useAutoOffsetAdjustmentContext() ?? {};
const {
fixedItemKeys
} = useCustomHandleContext() ?? {};
const othersIndexToKey = useInactiveIndexToKey();
const debugBox = useDebugBoundingBox();
const othersLayout = useDerivedValue(() => additionalCrossOffset?.value === null ? null : calculateLayout({
gaps: {
cross: crossGap.value,
main: mainGap.value
},
indexToKey: othersIndexToKey.value,
isVertical,
itemHeights: itemHeights.value,
itemWidths: itemWidths.value,
numGroups,
startCrossOffset: additionalCrossOffset?.value
}));
let mainContainerSize;
let crossContainerSize;
let mainCoordinate;
let crossCoordinate;
let crossDimension;
if (isVertical) {
mainContainerSize = containerWidth;
crossContainerSize = containerHeight;
mainCoordinate = 'x';
crossCoordinate = 'y';
crossDimension = 'height';
} else {
mainContainerSize = containerHeight;
crossContainerSize = containerWidth;
mainCoordinate = 'y';
crossCoordinate = 'x';
crossDimension = 'width';
}
return ({
activeIndex,
dimensions,
position
}) => {
'worklet';
if (!othersLayout.value || crossContainerSize.value === null || mainContainerSize.value === null || mainGroupSize.value === null) {
return;
}
const {
crossAxisOffsets
} = othersLayout.value;
const startCrossIndex = getCrossIndex(activeIndex, numGroups);
const startMainIndex = getMainIndex(activeIndex, numGroups);
const startCrossSize = dimensions[crossDimension];
let crossIndex = startCrossIndex;
let mainIndex = startMainIndex;
const getItemCrossSize = index => crossAxisOffsets[index] !== undefined && crossAxisOffsets[index + 1] !== undefined ? crossAxisOffsets[index + 1] - crossAxisOffsets[index] - crossGap.value : null;
// CROSS AXIS BOUNDS
// Before bound
let crossBeforeOffset = -Infinity;
let crossBeforeBound = Infinity;
let crossCurrentSize = startCrossSize;
do {
if (crossBeforeBound !== Infinity) {
crossIndex--;
}
crossBeforeOffset = crossAxisOffsets[crossIndex] ?? 0;
const crossBeforeSize = getItemCrossSize(crossIndex - 1);
if (crossBeforeSize) {
const swapOffset = ((crossAxisOffsets[crossIndex - 1] ?? 0) + crossBeforeOffset + crossCurrentSize) / 2;
const additionalBeforeOffset = getAdditionalSwapOffset(crossBeforeSize);
crossBeforeBound = swapOffset - additionalBeforeOffset;
crossCurrentSize = crossBeforeSize;
} else {
crossBeforeBound = 0;
}
} while (crossBeforeBound > 0 && position[crossCoordinate] < crossBeforeBound);
// After bound
let crossAfterOffset = Infinity;
let crossAfterBound = -Infinity;
crossCurrentSize = startCrossSize;
do {
if (crossAfterBound !== -Infinity) {
crossIndex++;
}
const nextCrossAxisOffset = crossAxisOffsets[crossIndex + 1];
if (!nextCrossAxisOffset) {
break;
}
crossAfterOffset = (crossAxisOffsets[crossIndex] ?? 0) + crossCurrentSize;
const crossAfterSize = getItemCrossSize(crossIndex + 1);
const swapOffset = (crossAfterOffset + nextCrossAxisOffset) / 2;
const additionalAfterOffset = getAdditionalSwapOffset(crossAfterSize);
crossAfterBound = swapOffset + additionalAfterOffset;
if (crossAfterSize) {
crossCurrentSize = crossAfterSize;
}
} while (crossAfterBound < crossContainerSize.value && position[crossCoordinate] > crossAfterBound);
// MAIN AXIS BOUNDS
const additionalOffset = getAdditionalSwapOffset(mainContainerSize.value);
// Before bound
let mainBeforeOffset = -Infinity;
let mainBeforeBound = Infinity;
do {
if (mainBeforeBound !== Infinity) {
mainIndex--;
}
mainBeforeOffset = mainIndex * (mainGroupSize.value + mainGap.value);
mainBeforeBound = mainBeforeOffset - additionalOffset;
} while (mainBeforeBound > 0 && position[mainCoordinate] < mainBeforeBound);
// After bound
let mainAfterOffset = Infinity;
let mainAfterBound = -Infinity;
do {
if (mainAfterBound !== -Infinity) {
mainIndex++;
}
mainAfterOffset = mainIndex * (mainGroupSize.value + mainGap.value) + mainGroupSize.value;
mainAfterBound = mainAfterOffset + additionalOffset;
} while (mainAfterBound < mainContainerSize.value && position[mainCoordinate] > mainAfterBound);
// DEBUG ONLY
if (debugBox) {
if (isVertical) {
debugBox.top.update({
x: mainBeforeBound,
y: crossBeforeBound
}, {
x: mainAfterBound,
y: Math.max(crossBeforeOffset, crossBeforeBound)
});
debugBox.bottom.update({
x: mainBeforeBound,
y: Math.min(crossAfterOffset, crossAfterBound)
}, {
x: mainAfterBound,
y: crossAfterBound
});
debugBox.left.update({
x: mainBeforeBound,
y: crossBeforeBound
}, {
x: mainBeforeOffset,
y: crossAfterBound
});
debugBox.right.update({
x: mainAfterOffset,
y: crossBeforeBound
}, {
x: mainAfterBound,
y: crossAfterBound
});
} else {
debugBox.top.update({
x: crossBeforeBound,
y: mainBeforeBound
}, {
x: crossAfterBound,
y: mainBeforeOffset
});
debugBox.bottom.update({
x: crossBeforeBound,
y: mainAfterBound
}, {
x: crossAfterBound,
y: mainAfterOffset
});
debugBox.left.update({
x: crossBeforeBound,
y: mainBeforeBound
}, {
x: Math.max(crossBeforeOffset, crossBeforeBound),
y: mainAfterBound
});
debugBox.right.update({
x: Math.min(crossAfterOffset, crossAfterBound),
y: mainAfterBound
}, {
x: crossAfterBound,
y: mainBeforeBound
});
}
}
const idxToKey = indexToKey.value;
const itemsCount = idxToKey.length;
const limitedCrossIndex = Math.max(0, Math.min(crossIndex, Math.floor((itemsCount - 1) / numGroups)));
const newIndex = Math.min(Math.max(0, limitedCrossIndex * numGroups + mainIndex), itemsCount - 1);
if (newIndex === activeIndex || fixedItemKeys?.value[idxToKey[newIndex]]) {
return;
}
// return the new order of items
return reorder(idxToKey, activeIndex, newIndex, fixedItemKeys?.value);
};
};
//# sourceMappingURL=common.js.map