Skip to content

Commit e4bd6cb

Browse files
committed
feat: support horizontal layout
Closes #42.
1 parent b8e3cd9 commit e4bd6cb

36 files changed

+769
-365
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22
[![GitHub License](https://img.shields.io/github/license/omahili/react-native-reorderable-list)](https://github.com/omahili/react-native-reorderable-list?tab=MIT-1-ov-file#readme)
33
[![NPM Version](https://img.shields.io/npm/v/react-native-reorderable-list)](https://www.npmjs.com/package/react-native-reorderable-list?activeTab=versions)
44
<br />
5-
![iOS](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple)
6-
![Android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android)
5+
[![iOS](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple)](https://developer.apple.com/ios)
6+
[![Android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android)](https://www.android.com)
77

88
# React Native Reorderable List
99

10-
A reorderable list for React Native applications, powered by Reanimated 🚀
10+
A reorderable list for React Native applications, powered by Reanimated 🚀.
1111

1212
![Demo](https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExanBuODMwN29scmxoNXY0MmZkcHpzZnFxYXE5eTVydzBsbHIyY3ZqMyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/T9uQrEnUCijeJOzSs9/giphy.gif)
1313

14+
### Features
15+
16+
- Drag & Drop FlatList
17+
- Vertical & Horizontal Mode
18+
- Layout Animations
19+
- Nested Lists
20+
- Custom Animations
21+
1422
## Index
1523

1624
- [Install](#install)
@@ -60,7 +68,7 @@ This component uses a [FlatList](https://reactnative.dev/docs/flatlist) and it e
6068
| Props | Type | Required | Default | Description |
6169
| ------------------------- | ------------------------------------------------ | -------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6270
| autoscrollThreshold | `number` | No | `0.1` | Threshold at the extremity of the list that triggers autoscroll when an item is dragged to it. A value of `0.1` means that 10% of the area at the top and 10% at the bottom will trigger autoscroll. Min value: `0`. Max value: `0.4`. |
63-
| autoscrollThresholdOffset | `{top?: number; bottom?: number}` | No | `{top: 0, bottom: 0}` | Amount by which the threshold is offset at the extremety of the list. For example, setting `{top: 50}` will make the autoscroll trigger 50 pixels earlier at the top. |
71+
| autoscrollThresholdOffset | `{start?: number; end?: number}` | No | `{start: 0, end: 0}` | Amount by which the threshold is offset at the extremety of the list. For example, setting `{start: 50}` will make the autoscroll trigger 50 pixels earlier at the start of the list. |
6472
| autoscrollSpeedScale | `number` | No | `1` | Scales the autoscroll speed at which the list scrolls when an item is dragged to the scroll areas. |
6573
| autoscrollDelay | `number` | No | `0` (Android), `100` (iOS) | Delay in between autoscroll triggers. Can be used to tune the autoscroll smoothness. Default values differ between platforms: `0` for Android and `100` for iOS. |
6674
| 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. |
@@ -78,7 +86,6 @@ This component uses a [FlatList](https://reactnative.dev/docs/flatlist) and it e
7886

7987
The following props from FlatList are not supported:
8088

81-
- horizontal
8289
- scrollEventThrottle
8390
- removeClippedSubviews
8491
- CellRendererComponent

example/src/ActiveItem.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React, {memo, useMemo, useState} from 'react';
2-
import {ListRenderItemInfo} from 'react-native';
2+
import {ListRenderItemInfo, StyleSheet} from 'react-native';
33

44
import {faker} from '@faker-js/faker';
5-
import ReorderableList, {
5+
import {
66
ReorderableListReorderEvent,
77
reorderItems,
88
useIsActive,
@@ -12,19 +12,15 @@ import {
1212
ItemSeparator,
1313
ListItem,
1414
ListItemProps,
15+
ReorderableList,
1516
SeedDataItem,
1617
usePanGesture,
1718
} from './common';
1819

1920
export const ActiveItem: React.FC<ListItemProps> = memo(props => {
2021
const isActive = useIsActive();
2122

22-
return (
23-
<ListItem
24-
{...props}
25-
description={isActive ? 'ACTIVE' : props.description}
26-
/>
27-
);
23+
return <ListItem style={isActive && styles.activeItem} {...props} />;
2824
});
2925

3026
export const ActiveItemScreen = () => {
@@ -37,6 +33,10 @@ export const ActiveItemScreen = () => {
3733
width: 50,
3834
height: 50,
3935
}),
36+
imageWidth: faker.number.int({
37+
min: 50,
38+
max: 90,
39+
}),
4040
title: faker.book.title(),
4141
description: faker.book.genre(),
4242
}),
@@ -69,3 +69,9 @@ export const ActiveItemScreen = () => {
6969
/>
7070
);
7171
};
72+
73+
const styles = StyleSheet.create({
74+
activeItem: {
75+
backgroundColor: 'lightblue',
76+
},
77+
});

example/src/CustomAnimations.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, {useMemo, useState} from 'react';
22
import {ListRenderItemInfo, Platform} from 'react-native';
33

44
import {Easing, useSharedValue, withTiming} from 'react-native-reanimated';
5-
import ReorderableList, {
5+
import {
66
ReorderableListCellAnimations,
77
ReorderableListDragEndEvent,
88
ReorderableListDragStartEvent,
@@ -13,6 +13,7 @@ import ReorderableList, {
1313
import {
1414
ItemSeparator,
1515
ListItem,
16+
ReorderableList,
1617
SeedDataItem,
1718
usePanGesture,
1819
useSeedData,

example/src/DragEnable.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import React, {useCallback, useMemo, useState} from 'react';
22
import {Button, ListRenderItemInfo, StyleSheet, View} from 'react-native';
33

44
import {Gesture} from 'react-native-gesture-handler';
5-
import ReorderableList, {
5+
import {
66
ReorderableListReorderEvent,
77
reorderItems,
88
} from 'react-native-reorderable-list';
99

10-
import {ItemSeparator, ListItem, SeedDataItem, useSeedData} from './common';
10+
import {
11+
ItemSeparator,
12+
ListItem,
13+
ReorderableList,
14+
SeedDataItem,
15+
useSeedData,
16+
} from './common';
1117

1218
export const DragEnableScreen = () => {
1319
const seedData = useSeedData();
@@ -58,7 +64,6 @@ export const DragEnableScreen = () => {
5864
const styles = StyleSheet.create({
5965
container: {
6066
flex: 1,
61-
paddingBottom: 32,
6267
},
6368
listContentContainer: {
6469
flexGrow: 1,
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import React, {useState} from 'react';
22
import {ListRenderItemInfo} from 'react-native';
33

4-
import ReorderableList, {
4+
import {
55
ReorderableListReorderEvent,
66
reorderItems,
77
} from 'react-native-reorderable-list';
88

99
import {
1010
ItemSeparator,
1111
ListItem,
12+
ReorderableList,
1213
SeedDataItem,
1314
usePanGesture,
1415
useSeedData,
1516
} from './common';
1617

17-
export const DynamicHeightsScreen = () => {
18+
export const DynamicSizesScreen = () => {
1819
const seedData = useSeedData();
1920
const [data, setData] = useState(seedData);
2021
const panGesture = usePanGesture();
Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,38 @@
11
import React, {useState} from 'react';
22
import {ListRenderItemInfo, Platform, StyleSheet, View} from 'react-native';
33

4-
import ReorderableList, {
4+
import {
55
ReorderableListReorderEvent,
66
reorderItems,
77
} from 'react-native-reorderable-list';
88

99
import {
1010
ItemSeparator,
1111
ListItem,
12+
ReorderableList,
1213
SeedDataItem,
1314
TitleHighlight,
15+
useHorizontal,
1416
usePanGesture,
1517
useSeedData,
1618
} from './common';
1719

18-
const TOP_HEIGHT = 150;
19-
const BOTTOM_HEIGHT = 100;
20+
const START_SIZE = 70;
21+
const END_SIZE = 60;
2022

21-
const contentInset = {top: TOP_HEIGHT, bottom: BOTTOM_HEIGHT};
22-
const autoscrollThresholdOffset = Platform.select({ios: contentInset});
23-
const contentOffset = Platform.select({ios: {y: -TOP_HEIGHT, x: 0}});
23+
const contentInsetVertical = {top: START_SIZE, bottom: END_SIZE};
24+
const contentInsetHorizontal = {left: START_SIZE, right: END_SIZE};
25+
const autoscrollThresholdOffset = Platform.select({
26+
ios: {start: START_SIZE, end: END_SIZE},
27+
});
28+
const contentOffsetVertical = Platform.select({ios: {y: -START_SIZE, x: 0}});
29+
const contentOffsetHorizontal = Platform.select({ios: {y: 0, x: -START_SIZE}});
2430

2531
export const FloatingHeaderFooterScreen = () => {
2632
const seedData = useSeedData();
2733
const [data, setData] = useState(seedData);
2834
const panGesture = usePanGesture();
35+
const {horizontal} = useHorizontal();
2936

3037
const handleReorder = ({from, to}: ReorderableListReorderEvent) => {
3138
setData(value => reorderItems(value, from, to));
@@ -38,8 +45,11 @@ export const FloatingHeaderFooterScreen = () => {
3845
return (
3946
<View style={styles.container}>
4047
<TitleHighlight
41-
title="Floating Top"
42-
style={[Platform.select({ios: styles.absoluteContainer}), styles.top]}
48+
title="Start"
49+
style={[
50+
Platform.select({ios: styles.absoluteContainer}),
51+
horizontal ? styles.left : styles.top,
52+
]}
4353
/>
4454
<ReorderableList
4555
data={data}
@@ -48,15 +58,19 @@ export const FloatingHeaderFooterScreen = () => {
4858
keyExtractor={item => item.id}
4959
ItemSeparatorComponent={ItemSeparator}
5060
autoscrollThresholdOffset={autoscrollThresholdOffset}
51-
contentInset={contentInset}
52-
contentOffset={contentOffset}
61+
contentInset={
62+
horizontal ? contentInsetHorizontal : contentInsetVertical
63+
}
64+
contentOffset={
65+
horizontal ? contentOffsetHorizontal : contentOffsetVertical
66+
}
5367
panGesture={panGesture}
5468
/>
5569
<TitleHighlight
56-
title="Floating Bottom"
70+
title="End"
5771
style={[
5872
Platform.select({ios: styles.absoluteContainer}),
59-
styles.bottom,
73+
horizontal ? styles.right : styles.bottom,
6074
]}
6175
/>
6276
</View>
@@ -69,17 +83,31 @@ const styles = StyleSheet.create({
6983
},
7084
absoluteContainer: {
7185
position: 'absolute',
72-
right: 0,
73-
left: 0,
7486
zIndex: 1,
7587
opacity: 0.75,
7688
},
7789
top: {
7890
top: 0,
79-
height: TOP_HEIGHT,
91+
right: 0,
92+
left: 0,
93+
height: START_SIZE,
8094
},
8195
bottom: {
8296
bottom: 0,
83-
height: BOTTOM_HEIGHT,
97+
right: 0,
98+
left: 0,
99+
height: END_SIZE,
100+
},
101+
left: {
102+
top: 0,
103+
left: 0,
104+
width: START_SIZE,
105+
height: '100%',
106+
},
107+
right: {
108+
top: 0,
109+
right: 0,
110+
width: END_SIZE,
111+
height: '100%',
84112
},
85113
});

example/src/HeaderFooter.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React, {useState} from 'react';
22
import {ListRenderItemInfo} from 'react-native';
33

4-
import ReorderableList, {
4+
import {
55
ReorderableListReorderEvent,
66
reorderItems,
77
} from 'react-native-reorderable-list';
88

99
import {
1010
ItemSeparator,
1111
ListItem,
12+
ReorderableList,
1213
SeedDataItem,
1314
TitleHighlight,
1415
usePanGesture,

example/src/Home.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@ export const HomeScreen = () => {
2121
)}
2222
keyExtractor={item => item.id}
2323
style={styles.list}
24+
contentContainerStyle={styles.listContentContainer}
2425
/>
2526
);
2627
};
2728

2829
const styles = StyleSheet.create({
2930
list: {
31+
flex: 1,
3032
backgroundColor: 'white',
3133
},
34+
listContentContainer: {
35+
flexGrow: 1,
36+
},
3237
item: {
3338
padding: 12,
3439
backgroundColor: 'white',

example/src/IndexChange.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, {useCallback, useState} from 'react';
22
import {ListRenderItemInfo, StyleSheet, View} from 'react-native';
33

44
import {runOnJS} from 'react-native-reanimated';
5-
import ReorderableList, {
5+
import {
66
ReorderableListReorderEvent,
77
reorderItems,
88
} from 'react-native-reorderable-list';
@@ -11,6 +11,7 @@ import {ReorderableListIndexChangeEvent} from 'src/types';
1111
import {
1212
ItemSeparator,
1313
ListItem,
14+
ReorderableList,
1415
SeedDataItem,
1516
TitleHighlight,
1617
usePanGesture,
@@ -74,7 +75,6 @@ const styles = StyleSheet.create({
7475
flex: 1,
7576
},
7677
footer: {
77-
height: 80,
78-
paddingBottom: 24,
78+
height: 60,
7979
},
8080
});

example/src/LayoutAnimations/LayoutAnimationsScreen.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import React, {useCallback, useState} from 'react';
22
import {Button, ListRenderItemInfo, StyleSheet, View} from 'react-native';
33

44
import {LinearTransition} from 'react-native-reanimated';
5-
import ReorderableList, {
5+
import {
66
ReorderableListReorderEvent,
77
reorderItems,
88
} from 'react-native-reorderable-list';
99

1010
import {
1111
ItemSeparator,
12+
ReorderableList,
1213
SeedDataItem,
1314
createDataItem,
1415
usePanGesture,

0 commit comments

Comments
 (0)