Skip to content

Commit 53d9c76

Browse files
committed
feat: add dragEnabled prop
Closes #52.
1 parent ffb0343 commit 53d9c76

File tree

8 files changed

+97
-10
lines changed

8 files changed

+97
-10
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ This component uses a [FlatList](https://reactnative.dev/docs/flatlist) and it e
6666
| autoscrollActivationDelta | `number` | No | `5` | Allows configuring the delta for autoscroll activation when dragging an item in the same direction as the autoscroll. This is particularly useful when an item is dragged within the autoscroll area to account for minor unintentional movements. |
6767
| animationDuration | `number` | No | `200` | Duration of the animations in milliseconds. Users won't be able to drag a new item until the dragged item is released and its animation to its new position ends. |
6868
| cellAnimations | `ReorderableListCellAnimations` | No | N/A | Allows passing an object with values and/or shared values that can animate a cell, for example by using the `onDragStart` and `onDragEnd` events. Supports view style properties. Override opacity and/or transform to disable the default animation, e.g. `{opacity: 1, transform: []}`. Check the [examples](https://github.com/omahili/react-native-reorderable-list/tree/master/example) for more details. |
69+
| dragEnabled | `boolean` | No | `true` | Whether dragging items is enabled. |
6970
| shouldUpdateActiveItem | boolean | No | `false` | Whether the active item should be updated. Enables usage of `useIsActive` hook. |
7071
| panGesture | `PanGesture` | No | N/A | Custom instance of pan gesture. See [GestureHandler docs](https://docs.swmansion.com/react-native-gesture-handler) for further info. |
7172
| onReorder | `(event: { from: number, to: number }) => void` | Yes | N/A | Event fired after an item is released and the list is reordered. |
@@ -96,7 +97,7 @@ This component allows nesting a reorderable list within a [ScrollViewContainer](
9697

9798
| Props | Type | Required | Default | Description |
9899
| ---------- | --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
99-
| scrollable | `boolean` | No | false | Whether the nested list is scrollable or not. If the nested list has a fixed height and it's scrollable it should be set to `true`, otherwise `false`. |
100+
| scrollable | `boolean` | No | `false` | Whether the nested list is scrollable or not. If the nested list has a fixed height and it's scrollable it should be set to `true`, otherwise `false`. |
100101

101102
## Hooks
102103

@@ -189,7 +190,7 @@ import {Gesture} from 'react-native-gesture-handler';
189190

190191
// If it doesn't work try with bigger values.
191192
const panGesture = useMemo(
192-
() => Gesture.Pan().activeOffsetX([-20, 20]).activeOffsetY(0),
193+
() => Gesture.Pan().activeOffsetX([-20, 20]).activeOffsetY([0, 0]),
193194
[],
194195
);
195196

example/src/ActiveItem.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ItemSeparator,
1212
ListItem,
1313
ListItemProps,
14+
SeedDataItem,
1415
usePanGesture,
1516
useSeedData,
1617
} from './common';
@@ -35,7 +36,7 @@ export const ActiveItemScreen = () => {
3536
setData(value => reorderItems(value, from, to));
3637
};
3738

38-
const renderItem = ({item}: ListRenderItemInfo<ListItemProps>) => (
39+
const renderItem = ({item}: ListRenderItemInfo<SeedDataItem>) => (
3940
<ActiveItem {...item} />
4041
);
4142

example/src/DragEnable.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React, {useCallback, useMemo, useState} from 'react';
2+
import {Button, ListRenderItemInfo, StyleSheet, View} from 'react-native';
3+
4+
import {Gesture} from 'react-native-gesture-handler';
5+
import ReorderableList, {
6+
ReorderableListReorderEvent,
7+
reorderItems,
8+
} from 'react-native-reorderable-list';
9+
10+
import {ItemSeparator, ListItem, SeedDataItem, useSeedData} from './common';
11+
12+
export const DragEnableScreen = () => {
13+
const seedData = useSeedData();
14+
const [data, setData] = useState(seedData);
15+
const [dragEnabled, setDragEnabled] = useState(false);
16+
17+
// Allows for navigation gestures.
18+
const panGesture = useMemo(
19+
() => Gesture.Pan().activeOffsetX([-20, 20]).activeOffsetY([0, 0]),
20+
[],
21+
);
22+
23+
const handleReorder = useCallback(
24+
({from, to}: ReorderableListReorderEvent) => {
25+
setData(value => reorderItems(value, from, to));
26+
},
27+
[],
28+
);
29+
30+
const renderItem = useCallback(
31+
({item}: ListRenderItemInfo<SeedDataItem>) => (
32+
<ListItem dragMode="press-in" {...item} />
33+
),
34+
[],
35+
);
36+
37+
const handleButtonPress = () => setDragEnabled(value => !value);
38+
39+
return (
40+
<View style={styles.container}>
41+
<ReorderableList
42+
data={data}
43+
onReorder={handleReorder}
44+
renderItem={renderItem}
45+
keyExtractor={item => item.id}
46+
ItemSeparatorComponent={ItemSeparator}
47+
panGesture={panGesture}
48+
dragEnabled={dragEnabled}
49+
/>
50+
<Button
51+
title={dragEnabled ? 'Disable drag' : 'Enable drag'}
52+
onPress={handleButtonPress}
53+
/>
54+
</View>
55+
);
56+
};
57+
58+
const styles = StyleSheet.create({
59+
container: {
60+
flex: 1,
61+
paddingBottom: 32,
62+
},
63+
listContentContainer: {
64+
flexGrow: 1,
65+
},
66+
});

example/src/common/ListItem.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ export interface ListItemProps {
77
image: string;
88
title: string;
99
description: string;
10+
dragMode?: 'press-in' | 'long-press';
1011
}
1112

1213
export const ListItem: React.FC<ListItemProps> = memo(
13-
({image, title, description}) => {
14+
({image, title, description, dragMode = 'long-press'}) => {
1415
const drag = useReorderableDrag();
1516

1617
return (
17-
<Pressable style={styles.container} onLongPress={drag}>
18+
<Pressable
19+
style={styles.container}
20+
onPressIn={dragMode === 'press-in' ? drag : undefined}
21+
onLongPress={dragMode === 'long-press' ? drag : undefined}>
1822
<Image
1923
style={styles.image}
2024
source={{

example/src/screens.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
33

44
import {ActiveItemScreen} from './ActiveItem';
55
import {CustomAnimationsScreen} from './CustomAnimations';
6+
import {DragEnableScreen} from './DragEnable';
67
import {DynamicHeightsScreen} from './DynamicHeights';
78
import {FloatingHeaderFooterScreen} from './FloatingHeaderFooter';
89
import {HeaderFooterScreen} from './HeaderFooter';
@@ -81,6 +82,11 @@ const screens = [
8182
name: 'Swipeable List',
8283
component: SwipeableListScreen,
8384
},
85+
{
86+
id: '13',
87+
name: 'Drag Enable',
88+
component: DragEnableScreen,
89+
},
8490
] as const;
8591

8692
const names = screens.map(x => x.name);

src/components/ReorderableListCore.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const ReorderableListCore = <T,>(
8585
scrollable,
8686
outerScrollGesture,
8787
cellAnimations,
88+
dragEnabled = true,
8889
shouldUpdateActiveItem,
8990
panGesture,
9091
panEnabled = true,
@@ -94,8 +95,7 @@ const ReorderableListCore = <T,>(
9495
}: ReorderableListCoreProps<T>,
9596
ref: React.ForwardedRef<FlatList<T>>,
9697
) => {
97-
const scrollEnabled =
98-
typeof rest.scrollEnabled === 'undefined' ? true : rest.scrollEnabled;
98+
const scrollEnabled = rest.scrollEnabled ?? true;
9999

100100
const flatListRef = useAnimatedRef<FlatList>();
101101
const [activeIndex, setActiveIndex] = useState(-1);
@@ -144,6 +144,7 @@ const ReorderableListCore = <T,>(
144144
const autoscrollActivationDeltaProp = usePropAsSharedValue(
145145
autoscrollActivationDelta,
146146
);
147+
const dragEnabledProp = usePropAsSharedValue(dragEnabled ?? true);
147148

148149
// Position of the list relative to the scroll container
149150
const nestedFlatListPositionY = useDerivedValue(
@@ -839,6 +840,10 @@ const ReorderableListCore = <T,>(
839840
(index: number) => {
840841
'worklet';
841842

843+
if (!dragEnabledProp.value) {
844+
return;
845+
}
846+
842847
// allow new drag when item is completely released
843848
if (state.value === ReorderableListState.IDLE) {
844849
// resetting shared values again fixes a flickeing bug in nested lists where
@@ -866,6 +871,7 @@ const ReorderableListCore = <T,>(
866871
}
867872
},
868873
[
874+
dragEnabledProp,
869875
resetSharedValues,
870876
shouldUpdateActiveItem,
871877
dragInitialScrollOffsetY,

src/components/ScrollViewContainer.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ const ScrollViewContainerWithRef = (
1919
{onLayout, onScroll, ...rest}: ScrollViewContainerProps,
2020
ref: React.ForwardedRef<ScrollView>,
2121
) => {
22-
const scrollEnabled =
23-
typeof rest.scrollEnabled === 'undefined' ? true : rest.scrollEnabled;
22+
const scrollEnabled = rest.scrollEnabled ?? true;
2423

2524
const scrollViewScrollEnabledProp = usePropAsSharedValue(scrollEnabled);
2625
const scrollViewCurrentScrollEnabled = useSharedValue(scrollEnabled);

src/types/props.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ export interface ReorderableListProps<T>
107107
* Allows passing an object with values and/or shared values that can animate a cell, for example by using the `onDragStart` and `onDragEnd` events. Supports view style properties. Override opacity and/or transform to disable the default animation, e.g. `{opacity: 1, transform: []}`.
108108
*/
109109
cellAnimations?: ReorderableListCellAnimations;
110+
/**
111+
* Whether dragging items is enabled. Default: `true`.
112+
*/
113+
dragEnabled?: boolean;
110114
/**
111115
* Whether the active item should be updated. Enables usage of `useIsActive` hook. Default: `false`.
112116
*/
@@ -116,7 +120,7 @@ export interface ReorderableListProps<T>
116120
*/
117121
panGesture?: PanGesture;
118122
/**
119-
* Wether the pan gestures necessary for dragging are enabled. Default: `true`.
123+
* Whether the pan gestures necessary for dragging are enabled. Default: `true`.
120124
*
121125
* @deprecated In favor of `panGesture` prop.
122126
*/

0 commit comments

Comments
 (0)