react-native-sortables
Version:
Powerful Sortable Components for Flexible Content Reordering in React Native
182 lines (173 loc) • 5.91 kB
JavaScript
;
import { reorderInsert, resolveDimension } from '../../../../../utils';
const getGroupItemIndex = (inGroupIndex, group, keyToIndex) => {
'worklet';
const key = group[inGroupIndex];
if (key === undefined) return null;
return keyToIndex[key] ?? null;
};
export const getTotalGroupSize = (group, mainItemSizes, gap) => {
'worklet';
const sizesSum = group.reduce((total, key) => total + (resolveDimension(mainItemSizes, key) ?? 0), 0);
return sizesSum + gap * (group.length - 1);
};
const getIndexesWhenSwappedToGroupBefore = ({
activeItemKey,
currentGroupIndex,
fixedKeys,
groupSizeLimit,
indexToKey,
itemGroups,
keyToIndex,
mainGap,
mainItemSizes
}) => {
'worklet';
if (groupSizeLimit === Infinity) {
return null;
}
const activeMainSize = resolveDimension(mainItemSizes, activeItemKey) ?? 0;
for (let groupIdx = currentGroupIndex; groupIdx > 0; groupIdx--) {
const groupBefore = itemGroups[groupIdx - 1];
const firstInGroupBeforeIndex = getGroupItemIndex(0, groupBefore, keyToIndex);
const lastInGroupBeforeIndex = getGroupItemIndex(groupBefore.length - 1, groupBefore, keyToIndex);
if (firstInGroupBeforeIndex === null || lastInGroupBeforeIndex === null) {
return null;
}
let itemIndex = firstInGroupBeforeIndex;
let totalGroupSize = 0;
const groupBeforeBefore = itemGroups[groupIdx - 2];
if (groupBeforeBefore) {
// If there is a group before the group before the active group,
// we have to check whether the active item won't wrap to this group
const totalGroupBeforeBeforeSize = getTotalGroupSize(groupBeforeBefore, mainItemSizes, mainGap);
const canBeFirstInGroupBefore = totalGroupBeforeBeforeSize + activeMainSize > groupSizeLimit;
if (!canBeFirstInGroupBefore) {
const firstItemKey = groupBefore[0];
if (firstItemKey === undefined) {
return null;
}
totalGroupSize += (resolveDimension(mainItemSizes, firstItemKey) ?? 0) + mainGap;
itemIndex++;
}
}
for (; itemIndex <= lastInGroupBeforeIndex; itemIndex++) {
const itemKey = indexToKey[itemIndex];
if (itemKey === undefined) {
return null;
}
if (totalGroupSize + activeMainSize > groupSizeLimit) {
break;
}
if (!fixedKeys?.[itemKey]) {
return {
groupIndex: groupIdx - 1,
itemIndex,
itemIndexInGroup: itemIndex - firstInGroupBeforeIndex
};
}
const itemMainSize = resolveDimension(mainItemSizes, itemKey) ?? 0;
totalGroupSize += itemMainSize + mainGap;
}
}
return null;
};
const getIndexesWhenSwappedToGroupAfter = ({
activeItemKey,
currentGroupIndex,
fixedKeys,
groupSizeLimit,
indexToKey,
itemGroups,
keyToIndex,
mainGap,
mainItemSizes
}) => {
'worklet';
const activeGroup = itemGroups[currentGroupIndex];
if (groupSizeLimit === Infinity || activeGroup === undefined) {
return null;
}
const firstInActiveGroupIndex = getGroupItemIndex(0, activeGroup, keyToIndex);
if (firstInActiveGroupIndex === null) {
return null;
}
const getItemMainSize = key => resolveDimension(mainItemSizes, key) ?? 0;
// We need to remove the active item from the its group, fit all items
// in the remaining space between the active item's group and the target group,
// and then insert the active item in the target group
const activeItemIndex = keyToIndex[activeItemKey];
let totalGroupSize = 0;
for (let i = firstInActiveGroupIndex; i < activeItemIndex; i++) {
const key = indexToKey[i];
totalGroupSize += getItemMainSize(key) + mainGap;
}
let firstInGroupIndex = firstInActiveGroupIndex;
let groupIndex = currentGroupIndex;
let emptyIndex = activeItemIndex;
const doesNotFitInGroup = key => totalGroupSize + getItemMainSize(key) > groupSizeLimit;
const includeItem = key => {
const itemMainSize = getItemMainSize(key);
if (doesNotFitInGroup(key)) {
groupIndex++;
totalGroupSize = 0;
firstInGroupIndex = keyToIndex[key];
}
totalGroupSize += itemMainSize + mainGap;
};
for (let i = activeItemIndex + 1; i < indexToKey.length; i++) {
const key = indexToKey[i];
if (fixedKeys?.[key]) {
continue;
}
// Fill the empty slot with the current item and add all fixed
// position items that were before this item
includeItem(key);
for (let j = emptyIndex + 1; j < i; j++) {
includeItem(indexToKey[j]);
}
emptyIndex = i;
if (doesNotFitInGroup(activeItemKey)) {
const nextItemKey = indexToKey[i + 1];
if (nextItemKey === undefined || doesNotFitInGroup(nextItemKey)) {
return {
groupIndex: groupIndex + 1,
itemIndex: i,
itemIndexInGroup: 0
};
}
} else if (groupIndex > currentGroupIndex) {
return {
groupIndex,
itemIndex: i,
itemIndexInGroup: i - firstInGroupIndex
};
}
}
return null;
};
export const getSwappedToGroupBeforeIndices = props => {
'worklet';
const indexes = getIndexesWhenSwappedToGroupBefore(props);
if (indexes === null) return null;
const indexToKey = reorderInsert(props.indexToKey, props.activeItemIndex, indexes.itemIndex, props.fixedKeys);
const keyToIndex = Object.fromEntries(indexToKey.map((key, index) => [key, index]));
return {
...indexes,
indexToKey,
keyToIndex
};
};
export const getSwappedToGroupAfterIndices = props => {
'worklet';
const indexes = getIndexesWhenSwappedToGroupAfter(props);
if (indexes === null) return null;
const indexToKey = reorderInsert(props.indexToKey, props.activeItemIndex, indexes.itemIndex, props.fixedKeys);
const keyToIndex = Object.fromEntries(indexToKey.map((key, index) => [key, index]));
return {
...indexes,
indexToKey,
keyToIndex
};
};
//# sourceMappingURL=utils.js.map