Skip to content

Commit d575d54

Browse files
author
Andres Garcia
committed
add Masonic/Multi Column support
1 parent d9bad02 commit d575d54

File tree

3 files changed

+51
-25
lines changed

3 files changed

+51
-25
lines changed

src/DraxList.tsx

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ import {
3636
import { defaultListItemLongPressDelay } from './params';
3737

3838
interface Shift {
39-
targetValue: number;
40-
animatedValue: Animated.Value;
39+
targetValue: Position;
40+
animatedValue: Animated.ValueXY;
4141
}
4242

4343
interface ListItemPayload {
@@ -137,8 +137,8 @@ export const DraxList = <T extends unknown>(
137137
itemMeasurements.push(undefined);
138138
registrations.push(undefined);
139139
shifts.push({
140-
targetValue: 0,
141-
animatedValue: new Animated.Value(0),
140+
targetValue: { x: 0, y: 0 },
141+
animatedValue: new Animated.ValueXY({ x: 0, y: 0 }),
142142
});
143143
}
144144
}
@@ -171,14 +171,15 @@ export const DraxList = <T extends unknown>(
171171
);
172172

173173
// Get shift transform for list item at index.
174-
const getShiftTransform = useCallback(
174+
const getShiftTransformStyle = useCallback(
175175
(index: number) => {
176-
const shift = shiftsRef.current[index]?.animatedValue ?? 0;
177-
return horizontal
178-
? [{ translateX: shift }]
179-
: [{ translateY: shift }];
176+
const shift = shiftsRef.current[index]?.animatedValue;
177+
const transform = shift
178+
? [{ translateX: shift.x }, { translateY: shift.y }]
179+
: [];
180+
return { transform };
180181
},
181-
[horizontal],
182+
[],
182183
);
183184

184185
// Set the currently dragged list item.
@@ -210,7 +211,7 @@ export const DraxList = <T extends unknown>(
210211
} = itemStyles ?? {};
211212
return (
212213
<DraxView
213-
style={[itemStyle, { transform: getShiftTransform(originalIndex) }]}
214+
style={[itemStyle, getShiftTransformStyle(originalIndex)]}
214215
draggingStyle={draggingStyle}
215216
dragReleasedStyle={dragReleasedStyle}
216217
{...otherStyleProps}
@@ -243,7 +244,7 @@ export const DraxList = <T extends unknown>(
243244
originalIndexes,
244245
itemStyles,
245246
viewPropsExtractor,
246-
getShiftTransform,
247+
getShiftTransformStyle,
247248
resetDraggedItem,
248249
itemsDraggable,
249250
renderItemContent,
@@ -368,8 +369,8 @@ export const DraxList = <T extends unknown>(
368369
() => {
369370
shiftsRef.current.forEach((shift) => {
370371
// eslint-disable-next-line no-param-reassign
371-
shift.targetValue = 0;
372-
shift.animatedValue.setValue(0);
372+
shift.targetValue = { x: 0, y: 0 };
373+
shift.animatedValue.setValue({ x: 0, y: 0 });
373374
});
374375
},
375376
[],
@@ -380,18 +381,36 @@ export const DraxList = <T extends unknown>(
380381
(
381382
{ index: fromIndex, originalIndex: fromOriginalIndex }: ListItemPayload,
382383
{ index: toIndex }: ListItemPayload,
384+
horizontalShift: boolean
383385
) => {
386+
const contentSize = contentSizeRef.current;
384387
const { width = 50, height = 50 } = itemMeasurementsRef.current[fromOriginalIndex] ?? {};
385-
const offset = horizontal ? width : height;
388+
const posOffset = horizontalShift && contentSize && width < contentSize.x
389+
? { x: width, y: 0 }
390+
: { x: 0, y: height };
391+
const negOffset = {
392+
x: posOffset.x * -1,
393+
y: posOffset.y * -1,
394+
};
386395
originalIndexes.forEach((originalIndex, index) => {
396+
const { width: itemWidth = 0, height: itemHeight = 0 } = itemMeasurementsRef.current[originalIndex] ?? {};
387397
const shift = shiftsRef.current[originalIndex];
388-
let newTargetValue = 0;
398+
if (!shift) {
399+
return;
400+
}
401+
let newTargetValue = { x: 0, y: 0 };
389402
if (index > fromIndex && index <= toIndex) {
390-
newTargetValue = -offset;
403+
newTargetValue = negOffset;
391404
} else if (index < fromIndex && index >= toIndex) {
392-
newTargetValue = offset;
405+
newTargetValue = posOffset;
406+
}
407+
// Keep from shifting full width items horizontally
408+
if (contentSize && itemWidth >= contentSize.x) {
409+
if (!itemHeight) return;
410+
newTargetValue.x = 0;
393411
}
394-
if (shift.targetValue !== newTargetValue) {
412+
if (itemHeight && (shift.targetValue.x !== newTargetValue.x
413+
|| shift.targetValue.y !== newTargetValue.y)) {
395414
shift.targetValue = newTargetValue;
396415
Animated.timing(shift.animatedValue, {
397416
duration: 200,
@@ -401,7 +420,7 @@ export const DraxList = <T extends unknown>(
401420
}
402421
});
403422
},
404-
[originalIndexes, horizontal],
423+
[originalIndexes],
405424
);
406425

407426
// Calculate absolute position of list item for snapback.
@@ -573,7 +592,7 @@ export const DraxList = <T extends unknown>(
573592
// Monitor drags to react with item shifts and auto-scrolling.
574593
const onMonitorDragOver = useCallback(
575594
(eventData: DraxMonitorEventData) => {
576-
const { dragged, receiver, monitorOffsetRatio } = eventData;
595+
const { dragTranslation, dragged, receiver, monitorOffsetRatio } = eventData;
577596
// First, check if we need to shift items.
578597
if (reorderable && dragged.parentId === id) {
579598
// One of our list items is being dragged.
@@ -597,8 +616,10 @@ export const DraxList = <T extends unknown>(
597616
draggedToIndex.current = toIndex;
598617
}
599618

619+
const horizontalShift = (Math.abs(dragTranslation.x) > Math.abs(dragTranslation.y))
620+
600621
// Update shift transforms for items in the list.
601-
updateShifts(fromPayload, toPayload ?? fromPayload);
622+
updateShifts(fromPayload, toPayload ?? fromPayload, horizontalShift);
602623
}
603624

604625
// Next, see if we need to auto-scroll.

src/DraxProvider.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from './types';
2121
import { getRelativePosition } from './math';
2222

23-
export const DraxProvider: FunctionComponent<DraxProviderProps> = ({ debug = false, children }) => {
23+
export const DraxProvider: FunctionComponent<DraxProviderProps> = ({ debug = false, multicolumn = false, children }) => {
2424
const {
2525
getViewState,
2626
getTrackingStatus,
@@ -387,10 +387,10 @@ export const DraxProvider: FunctionComponent<DraxProviderProps> = ({ debug = fal
387387
* NOTE: if view is transformed, these will be wrong.
388388
*/
389389
const dragAbsolutePosition = {
390-
x: absoluteX + grabX,
390+
x: multicolumn ? absoluteX : absoluteX + grabX,
391391
y: absoluteY + grabY,
392392
};
393-
const grabOffset = { x: grabX, y: grabY };
393+
const grabOffset = { x: multicolumn ? 0 : grabX, y: grabY };
394394
const grabOffsetRatio = {
395395
x: grabX / width,
396396
y: grabY / height,

src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
StyleProp,
88
ScrollViewProps,
99
ListRenderItemInfo,
10+
NativeScrollEvent,
1011
} from 'react-native';
1112
import {
1213
LongPressGestureHandlerStateChangeEvent,
@@ -583,6 +584,7 @@ export interface DraxContextValue {
583584
/** Optional props that can be passed to a DraxProvider to modify its behavior */
584585
export interface DraxProviderProps {
585586
debug?: boolean;
587+
multicolumn?: boolean;
586588
}
587589

588590
/** Props that are passed to a DraxSubprovider, used internally for nesting views */
@@ -878,6 +880,9 @@ export interface DraxListProps<TItem> extends Omit<FlatListProps<TItem>, 'render
878880
/** Callback handler for when a list item is moved within the list, reordering the list */
879881
onItemReorder?: DraxListOnItemReorder<TItem>;
880882

883+
/** Callback handler for when list is scrolled */
884+
onScrollProp?: (scrollEvent: NativeScrollEvent) => void;
885+
881886
/** Can the list be reordered by dragging items? Defaults to true if onItemReorder is set. */
882887
reorderable?: boolean;
883888

0 commit comments

Comments
 (0)