Skip to content

Commit

Permalink
feat: add onIndexChange event
Browse files Browse the repository at this point in the history
  • Loading branch information
omahili committed Jan 27, 2025
1 parent 936000f commit 5ea588b
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ This component uses a [FlatList](https://reactnative.dev/docs/flatlist) and it e
| 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. |
| shouldUpdateActiveItem | boolean | No | `false` | Whether the active item should be updated. Enables usage of `useIsActive` hook. |
| panEnabled | `boolean` | No | `true` | Wether the pan gestures necessary for dragging are enabled. |
| panActivateAfterLongPress | `number` | No | N/A | Duration in milliseconds a the long press on the list before pan gestures, necessary for dragging, are allowed to activate. |
| panActivateAfterLongPress | `number` | No | N/A | Duration in milliseconds of the long press on the list before the pan gesture for dragging is allowed to activate. |
| onReorder | `(event: { from: number, to: number }) => void` | Yes | N/A | Event fired after an item is released and the list is reordered. |
| onDragStart | `(event: { index: number }) => void` | No | N/A | Event fired when an item is dragged. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info. |
| onDragEnd | `(event: { from: number, to: number }) => void` | No | N/A | Event fired when the dragged item is released. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info. |
| onIndexChange | `(event: { index: number }) => void` | No | N/A | Event fired when the index of the dragged item changes. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info. |
| onScroll | `ReturnType<typeof useAnimatedScrollHandler>` | No | N/A | An animated scroll handler created with useAnimatedScrollHandler. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info. |

The following props from FlatList are not supported:
Expand Down
77 changes: 77 additions & 0 deletions example/src/IndexChange.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, {useCallback, useState} from 'react';
import {ListRenderItemInfo, StyleSheet, View} from 'react-native';

import {runOnJS} from 'react-native-reanimated';
import ReorderableList, {
ReorderableListReorderEvent,
reorderItems,
} from 'react-native-reorderable-list';
import {ReorderableListIndexChangeEvent} from 'src/types';

import {
ItemSeparator,
ListItem,
SeedDataItem,
TitleHighlight,
useSeedData,
} from './common';

export const IndexChangeScreen = () => {
const seedData = useSeedData();
const [data, setData] = useState(seedData);
const [currentIndex, setCurrentIndex] = useState<number>();

const handleReorder = ({from, to}: ReorderableListReorderEvent) => {
setData(value => reorderItems(value, from, to));
};

const renderItem = ({item}: ListRenderItemInfo<SeedDataItem>) => (
<ListItem {...item} />
);

const handleDragEnd = useCallback(() => {
'worklet';

runOnJS(setCurrentIndex)(undefined);
}, []);

const handleIndexChange = useCallback(
(e: ReorderableListIndexChangeEvent) => {
'worklet';

runOnJS(setCurrentIndex)(e.index);
},
[],
);

return (
<View style={styles.container}>
<ReorderableList
data={data}
onReorder={handleReorder}
renderItem={renderItem}
keyExtractor={item => item.id}
ItemSeparatorComponent={ItemSeparator}
onDragEnd={handleDragEnd}
onDragStart={handleIndexChange} // to register index at start
onIndexChange={handleIndexChange}
/>
<TitleHighlight
title={`Current ${
currentIndex !== undefined ? currentIndex : 'unknown'
}`}
style={styles.footer}
/>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
},
footer: {
height: 80,
paddingBottom: 24,
},
});
6 changes: 6 additions & 0 deletions example/src/screens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {CustomAnimationsScreen} from './CustomAnimations';
import {DynamicHeightsScreen} from './DynamicHeights';
import {FloatingHeaderScreen} from './FloatingHeader';
import {HeaderFooterScreen} from './HeaderFooter';
import {IndexChangeScreen} from './IndexChange';
import {MultipleListsScreen} from './MultipleLists';
import {NestedListsScreen} from './NestedLists';
import {NestedScrollableListsScreen} from './NestedScrollableLists';
Expand Down Expand Up @@ -69,6 +70,11 @@ const screens = [
name: 'Floating Header',
component: FloatingHeaderScreen,
},
{
id: '11',
name: 'Index Change',
component: IndexChangeScreen,
},
] as const;

const names = screens.map(x => x.name);
Expand Down
2 changes: 2 additions & 0 deletions src/components/ReorderableListCore/ReorderableListCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const ReorderableListCore = <T,>(
onScroll,
onDragStart,
onDragEnd,
onIndexChange,
scrollViewContainerRef,
scrollViewHeightY,
scrollViewScrollOffsetY,
Expand Down Expand Up @@ -93,6 +94,7 @@ const ReorderableListCore = <T,>(
onReorder,
onDragStart,
onDragEnd,
onIndexChange,
scrollViewContainerRef,
scrollViewHeightY,
scrollViewScrollOffsetY,
Expand Down
6 changes: 6 additions & 0 deletions src/components/ReorderableListCore/useReorderableListCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
ReorderableListCellAnimations,
ReorderableListDragEndEvent,
ReorderableListDragStartEvent,
ReorderableListIndexChangeEvent,
ReorderableListState,
} from '../../types';
import type {ReorderableListReorderEvent} from '../../types';
Expand All @@ -51,6 +52,7 @@ interface UseReorderableListCoreArgs<T> {
onReorder: (event: ReorderableListReorderEvent) => void;
onDragStart?: (event: ReorderableListDragStartEvent) => void;
onDragEnd?: (event: ReorderableListDragEndEvent) => void;
onIndexChange?: (event: ReorderableListIndexChangeEvent) => void;
onLayout?: (event: LayoutChangeEvent) => void;
scrollViewContainerRef: React.RefObject<ScrollView> | undefined;
scrollViewHeightY: SharedValue<number> | undefined;
Expand All @@ -77,6 +79,7 @@ export const useReorderableListCore = <T>({
onDragStart,
onDragEnd,
onLayout,
onIndexChange,
scrollViewContainerRef,
scrollViewHeightY,
scrollViewScrollOffsetY,
Expand Down Expand Up @@ -351,6 +354,8 @@ export const useReorderableListCore = <T>({
previousDirection.value = newDirection;
previousIndex.value = currentIndex.value;
currentIndex.value = newIndex;

onIndexChange?.({index: newIndex});
}
},
[
Expand All @@ -361,6 +366,7 @@ export const useReorderableListCore = <T>({
itemOffset,
itemHeight,
getIndexFromY,
onIndexChange,
],
);

Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
ReorderableListCellAnimations,
ReorderableListDragEndEvent,
ReorderableListDragStartEvent,
ReorderableListIndexChangeEvent,
ReorderableListProps,
ReorderableListReorderEvent,
ScrollViewContainerProps,
Expand All @@ -29,6 +30,7 @@ export {
ReorderableListCellAnimations,
ReorderableListDragStartEvent,
ReorderableListDragEndEvent,
ReorderableListIndexChangeEvent,
ScrollViewContainer,
ScrollViewContainerProps,
NestedReorderableList,
Expand Down
13 changes: 12 additions & 1 deletion src/types/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ export interface ReorderableListDragStartEvent {
index: number;
}

export interface ReorderableListIndexChangeEvent {
/**
* Index of the dragged item.
*/
index: number;
}

export interface ReorderableListDragEndEvent {
/**
* Index of the dragged item.
Expand Down Expand Up @@ -107,7 +114,7 @@ export interface ReorderableListProps<T>
*/
panEnabled?: boolean;
/**
* Duration in milliseconds of a long press on the list before pan gestures, necessary for dragging, are allowed to activate.
* Duration in milliseconds of the long press on the list before the pan gesture for dragging is allowed to activate.
*/
panActivateAfterLongPress?: number;
/**
Expand All @@ -126,6 +133,10 @@ export interface ReorderableListProps<T>
* Event fired when the dragged item is released. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.
*/
onDragEnd?: (event: ReorderableListDragEndEvent) => void;
/**
* Event fired when the index of the dragged item changes. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.
*/
onIndexChange?: (event: ReorderableListIndexChangeEvent) => void;
}

export type Transforms = PerspectiveTransform &
Expand Down

0 comments on commit 5ea588b

Please sign in to comment.