Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const SortableFlexInner = memo(function SortableFlexInner({
paddingRight,
paddingTop,
paddingVertical,
reorderOnDrag,
rowGap,
showDropIndicator,
strategy,
Expand Down Expand Up @@ -158,6 +159,7 @@ const SortableFlexInner = memo(function SortableFlexInner({
itemEntering={itemEntering}
itemExiting={itemExiting}
overflow={overflow}
reorderOnDrag={reorderOnDrag}
showDropIndicator={showDropIndicator}
strategy={strategy}
styleProps={styleProps}
Expand All @@ -175,13 +177,15 @@ type SortableFlexComponentProps = Pick<
| 'itemEntering'
| 'itemExiting'
| 'overflow'
| 'reorderOnDrag'
| 'showDropIndicator'
| 'strategy'
> & {
styleProps: FlexStyleProps;
};

function SortableFlexComponent({
reorderOnDrag,
strategy,
styleProps,
...rest
Expand All @@ -199,7 +203,7 @@ function SortableFlexComponent({
width
} = styleProps;

useOrderUpdater(strategy, FLEX_STRATEGIES);
useOrderUpdater(strategy, FLEX_STRATEGIES, reorderOnDrag);

const baseContainerStyle: ViewStyle = {
...styleProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const SortableGridInner = typedMemo(function SortableGridInner<I>({
itemEntering,
itemExiting,
overflow,
reorderOnDrag,
rowGap: _rowGap,
rowHeight,
showDropIndicator,
Expand Down Expand Up @@ -156,6 +157,7 @@ const SortableGridInner = typedMemo(function SortableGridInner<I>({
itemEntering={itemEntering}
itemExiting={itemExiting}
overflow={overflow}
reorderOnDrag={reorderOnDrag}
rowGap={rowGap}
rowHeight={rowHeight}
showDropIndicator={showDropIndicator}
Expand All @@ -176,6 +178,7 @@ type SortableGridComponentProps<I> = Pick<
| 'itemEntering'
| 'itemExiting'
| 'overflow'
| 'reorderOnDrag'
| 'rowHeight'
| 'showDropIndicator'
| 'strategy'
Expand All @@ -188,6 +191,7 @@ function SortableGridComponent<I>({
columnGap,
groups,
isVertical,
reorderOnDrag,
rowGap,
rowHeight,
strategy,
Expand All @@ -199,7 +203,7 @@ function SortableGridComponent<I>({

const isFirstRenderRef = useRef(true);

useOrderUpdater(strategy, GRID_STRATEGIES);
useOrderUpdater(strategy, GRID_STRATEGIES, reorderOnDrag);

useLayoutEffect(() => {
if (isFirstRenderRef.current) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-sortables/src/constants/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const DEFAULT_SHARED_PROPS = {
onOrderChange: undefined,
overDrag: 'both',
overflow: 'visible',
reorderOnDrag: true,
reorderTriggerOrigin: 'center',
scrollableRef: undefined,
showDropIndicator: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
const currentTouch = useMutableValue<null | TouchData>(null);
// Used to trigger order change of items when the active item is dragged around
const triggerOriginPosition = useMutableValue<null | Vector>(null);
// Order computed during a `reorderOnDrag={false}` drag. It isn't applied while
// dragging - it's committed in handleDragEnd before the drag-end callbacks fire.
const pendingDropOrder = useMutableValue<Array<string> | null>(null);

// ACTIVE ITEM POSITION UPDATER
useAnimatedReaction(
Expand Down Expand Up @@ -526,7 +529,30 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
}

const fromIndex = ctx.dragStartIndex;
const toIndex = keyToIndex.value[key]!;

// Commit a deferred (reorderOnDrag=false) reorder synchronously here so the
// drag-end callbacks below report the final order rather than the pre-drop
// one. With reorderOnDrag=true pendingDropOrder stays null and this is a no-op.
let dropIndexToKey = indexToKey.value;
let dropKeyToIndex = keyToIndex.value;
const newOrder = pendingDropOrder.value;
if (newOrder) {
pendingDropOrder.value = null;
indexToKey.value = newOrder;
dropIndexToKey = newOrder;
dropKeyToIndex = getKeyToIndex(newOrder);
const reorderedIndex = dropKeyToIndex[key]!;
if (reorderedIndex !== fromIndex) {
onOrderChange({
fromIndex,
indexToKey: newOrder,
key,
keyToIndex: dropKeyToIndex,
toIndex: reorderedIndex
});
}
}
const toIndex = dropKeyToIndex[key]!;

prevActiveItemKey.value = activeItemKey.value;
ctx.dragStartItemTouchOffset = null;
Expand Down Expand Up @@ -554,9 +580,9 @@ const { DragProvider, useDragContext } = createProvider('Drag')<

stableOnDragEnd({
fromIndex,
indexToKey: indexToKey.value,
indexToKey: dropIndexToKey,
key,
keyToIndex: keyToIndex.value,
keyToIndex: dropKeyToIndex,
toIndex
});

Expand All @@ -565,9 +591,9 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
updateLayer?.(LayerState.IDLE);
onActiveItemDropped({
fromIndex,
indexToKey: indexToKey.value,
indexToKey: dropIndexToKey,
key,
keyToIndex: keyToIndex.value,
keyToIndex: dropKeyToIndex,
toIndex
});
}, dropDuration);
Expand All @@ -590,6 +616,8 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
keyToIndex,
multiZoneActiveItemDimensions,
onActiveItemDropped,
onOrderChange,
pendingDropOrder,
stableOnDragEnd,
touchPosition,
updateLayer,
Expand Down Expand Up @@ -625,6 +653,7 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
handleOrderChange,
handleTouchesMove,
handleTouchStart,
pendingDropOrder,
triggerOriginPosition
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { useDragContext } from '../DragProvider';

export default function useOrderUpdater<
P extends PredefinedStrategies = PredefinedStrategies
>(strategy: keyof P | SortStrategyFactory, predefinedStrategies: P) {
>(
strategy: keyof P | SortStrategyFactory,
predefinedStrategies: P,
reorderOnDrag: boolean
) {
const useStrategy =
typeof strategy === 'string' ? predefinedStrategies[strategy] : strategy;

Expand All @@ -18,7 +22,8 @@ export default function useOrderUpdater<

const { activeItemDimensions, activeItemKey, keyToIndex } =
useCommonValuesContext();
const { handleOrderChange, triggerOriginPosition } = useDragContext();
const { handleOrderChange, pendingDropOrder, triggerOriginPosition } =
useDragContext();
const debugContext = useDebugContext();

const debugCross = debugContext?.useDebugCross();
Expand Down Expand Up @@ -53,13 +58,22 @@ export default function useOrderUpdater<
position
});

if (newOrder) {
if (!newOrder) {
return;
}

if (reorderOnDrag) {
handleOrderChange(
activeKey,
activeIndex,
newOrder.indexOf(activeKey),
newOrder
);
} else {
// Keep computing the prospective order during the drag but don't apply
// it yet. It's committed in handleDragEnd right before onDragEnd fires,
// so the drag-end callbacks report the final order (see DragProvider).
pendingDropOrder.value = newOrder;
}
}
);
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native-sortables/src/types/props/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ export type SharedProps = Simplify<
* @default 'visible'
*/
overflow: Overflow;
/** Whether to reorder items during drag gesture or after the active item is dropped
* @default true
*/
reorderOnDrag: boolean;
/** Enables debug mode to show additional visual helpers and console logs.
* @note This only works in development builds and has no effect in production.
* @default false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export type AutoScrollContextType = {

export type DragContextType = {
triggerOriginPosition: SharedValue<null | Vector>;
pendingDropOrder: SharedValue<Array<string> | null>;
handleTouchStart: (
e: GestureTouchEvent,
key: string,
Expand Down
Loading