Skip to content

Commit cf35be0

Browse files
authored
feat: Add item context, add working touchable (#121)
## Description This PR implements ItemContext which exposes item-related shared values that can be accessed by the user in their item component implementation. It also is useful for the custom touchable component implementation which is necessary for proper touch handling (Pressable and Touchable components fired `onPress` callback even though it should be cancelled).
1 parent c18de1b commit cf35be0

25 files changed

+344
-202
lines changed

example/app/src/components/cards/SortableFlexCard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StyleSheet } from 'react-native';
2-
import { SortableFlex } from 'react-native-sortable';
2+
import Sortable from 'react-native-sortable';
33

44
import { FlexCell } from '@/components';
55
import { useItemOrderChange } from '@/hooks';
@@ -19,13 +19,13 @@ const SortableFlexCard: RouteCardComponent = props => {
1919

2020
return (
2121
<RouteCard {...props}>
22-
<SortableFlex sortEnabled={false} style={styles.container}>
22+
<Sortable.Flex sortEnabled={false} style={styles.container}>
2323
{data.map(item => (
2424
<FlexCell active={item === ACTIVE_ITEM} key={item}>
2525
{item}
2626
</FlexCell>
2727
))}
28-
</SortableFlex>
28+
</Sortable.Flex>
2929
</RouteCard>
3030
);
3131
};

example/app/src/components/cards/SortableGridCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useCallback } from 'react';
22
import type { SortableGridRenderItem } from 'react-native-sortable';
3-
import { SortableGrid } from 'react-native-sortable';
3+
import Sortable from 'react-native-sortable';
44

55
import { GridCard } from '@/components';
66
import { useItemOrderChange } from '@/hooks';
@@ -26,7 +26,7 @@ const SortableGridCard: RouteCardComponent = props => {
2626

2727
return (
2828
<RouteCard {...props}>
29-
<SortableGrid
29+
<Sortable.Grid
3030
columnGap={spacing.xxs}
3131
columns={COLUMNS}
3232
data={data}

example/app/src/examples/SortableFlex/AutoScrollExample.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { AnimatedFlashList, type FlashList } from '@shopify/flash-list';
22
import { StyleSheet, Text } from 'react-native';
33
import type { AnimatedRef } from 'react-native-reanimated';
44
import Animated, { useAnimatedRef } from 'react-native-reanimated';
5-
import { SortableFlex } from 'react-native-sortable';
5+
import Sortable from 'react-native-sortable';
66

77
import { FlexCell, Group, Section, TabView } from '@/components';
88
import { colors, spacing } from '@/theme';
@@ -115,25 +115,25 @@ type CategoriesSectionProps = {
115115

116116
function ManyCategories({ scrollableRef }: CategoriesSectionProps) {
117117
return (
118-
<SortableFlex scrollableRef={scrollableRef} style={styles.sortableFlex}>
118+
<Sortable.Flex scrollableRef={scrollableRef} style={styles.sortableFlex}>
119119
{MANY_CATEGORIES.map(item => (
120120
<FlexCell key={item} size='large'>
121121
{item}
122122
</FlexCell>
123123
))}
124-
</SortableFlex>
124+
</Sortable.Flex>
125125
);
126126
}
127127

128128
function FewCategories({ scrollableRef }: CategoriesSectionProps) {
129129
return (
130-
<SortableFlex scrollableRef={scrollableRef} style={styles.sortableFlex}>
130+
<Sortable.Flex scrollableRef={scrollableRef} style={styles.sortableFlex}>
131131
{FEW_CATEGORIES.map(item => (
132132
<FlexCell key={item} size='large'>
133133
{item}
134134
</FlexCell>
135135
))}
136-
</SortableFlex>
136+
</Sortable.Flex>
137137
);
138138
}
139139

example/app/src/examples/SortableFlex/CallbacksExample.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { useCallback } from 'react';
22
import { StyleSheet } from 'react-native';
33
import { useSharedValue } from 'react-native-reanimated';
4-
import {
4+
import Sortable, {
55
type DragEndCallback,
66
type DragStartCallback,
7-
type OrderChangeCallback,
8-
SortableFlex
7+
type OrderChangeCallback
98
} from 'react-native-sortable';
109

1110
import { AnimatedText, FlexCell, Section, Stagger } from '@/components';
@@ -46,7 +45,7 @@ export default function CallbacksExample() {
4645
<Section
4746
description='Drag items around to see callbacks output'
4847
title='SortableFlex'>
49-
<SortableFlex
48+
<Sortable.Flex
5049
style={styles.sortableFlex}
5150
onDragEnd={onDragEnd}
5251
onDragStart={onDragStart}
@@ -56,7 +55,7 @@ export default function CallbacksExample() {
5655
{item}
5756
</FlexCell>
5857
))}
59-
</SortableFlex>
58+
</Sortable.Flex>
6059
</Section>
6160
</Stagger>
6261
);

example/app/src/examples/SortableFlex/DataChangeExample.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback, useState } from 'react';
2-
import { Pressable, StyleSheet, Text, View } from 'react-native';
2+
import { StyleSheet, Text, View } from 'react-native';
33
import Animated, { useAnimatedRef } from 'react-native-reanimated';
4-
import { SortableFlex, useDragEndHandler } from 'react-native-sortable';
4+
import Sortable, { useDragEndHandler } from 'react-native-sortable';
55

66
import { Button, FlexCell, Group, Section, Stagger } from '@/components';
77
import { colors, flex, spacing } from '@/theme';
@@ -126,16 +126,18 @@ export default function DataChangeExample() {
126126
<Text style={styles.title}>Above SortableFlex</Text>
127127
</Group>
128128

129-
<SortableFlex
129+
<Sortable.Flex
130130
scrollableRef={scrollableRef}
131131
style={styles.sortableFlex}
132132
onDragEnd={onDragEnd}>
133133
{data.map(item => (
134-
<Pressable key={item} onPress={onRemoveItem.bind(null, item)}>
134+
<Sortable.Pressable
135+
key={item}
136+
onPress={onRemoveItem.bind(null, item)}>
135137
<FlexCell size='large'>{item}</FlexCell>
136-
</Pressable>
138+
</Sortable.Pressable>
137139
))}
138-
</SortableFlex>
140+
</Sortable.Flex>
139141

140142
<Group withMargin={false} bordered center>
141143
<Text style={styles.title}>Below SortableFlex</Text>

example/app/src/examples/SortableFlex/DropIndicatorExample.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ScrollView, StyleSheet } from 'react-native';
2-
import { SortableFlex, SortableLayer } from 'react-native-sortable';
2+
import Sortable from 'react-native-sortable';
33

44
import { FlexCell, Section, Stagger } from '@/components';
55
import { CustomDropIndicator } from '@/examples/custom';
@@ -11,21 +11,21 @@ const DATA = getCategories(9);
1111
export default function DropIndicatorExample() {
1212
return (
1313
<ScrollView>
14-
<Stagger ParentComponent={SortableLayer}>
14+
<Stagger ParentComponent={Sortable.Layer}>
1515
<Section title='Without drop indicator'>
16-
<SortableFlex style={styles.sortableFlex}>
16+
<Sortable.Flex style={styles.sortableFlex}>
1717
{DATA.map(item => (
1818
<FlexCell key={item} size='large'>
1919
{item}
2020
</FlexCell>
2121
))}
22-
</SortableFlex>
22+
</Sortable.Flex>
2323
</Section>
2424

2525
<Section
2626
description='With custom style that changes border radius of the default drop indicator'
2727
title='Default drop indicator'>
28-
<SortableFlex
28+
<Sortable.Flex
2929
dropIndicatorStyle={styles.dropIndicatorStyle}
3030
style={styles.sortableFlex}
3131
showDropIndicator>
@@ -34,13 +34,13 @@ export default function DropIndicatorExample() {
3434
{item}
3535
</FlexCell>
3636
))}
37-
</SortableFlex>
37+
</Sortable.Flex>
3838
</Section>
3939

4040
<Section
4141
description='Looks better without inactive item opacity, so inactiveItemOpacity is set to 1 in this example'
4242
title='Custom drop indicator'>
43-
<SortableFlex
43+
<Sortable.Flex
4444
DropIndicatorComponent={CustomDropIndicator}
4545
dropIndicatorStyle={styles.dropIndicatorStyle}
4646
inactiveItemOpacity={1}
@@ -51,7 +51,7 @@ export default function DropIndicatorExample() {
5151
{item}
5252
</FlexCell>
5353
))}
54-
</SortableFlex>
54+
</Sortable.Flex>
5555
</Section>
5656
</Stagger>
5757
</ScrollView>

example/app/src/examples/SortableGrid/AutoScrollExample.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AnimatedFlashList } from '@shopify/flash-list';
33
import { StyleSheet, Text } from 'react-native';
44
import type { AnimatedRef } from 'react-native-reanimated';
55
import Animated, { useAnimatedRef } from 'react-native-reanimated';
6-
import { SortableGrid } from 'react-native-sortable';
6+
import Sortable from 'react-native-sortable';
77

88
import { GridCard, Group, Section, TabView } from '@/components';
99
import { colors, spacing } from '@/theme';
@@ -116,7 +116,7 @@ type CardsSectionProps = {
116116

117117
function ManyCards({ scrollableRef }: CardsSectionProps) {
118118
return (
119-
<SortableGrid
119+
<Sortable.Grid
120120
columnGap={spacing.sm}
121121
columns={3}
122122
data={MANY_ITEMS}
@@ -129,7 +129,7 @@ function ManyCards({ scrollableRef }: CardsSectionProps) {
129129

130130
function FewCards({ scrollableRef }: CardsSectionProps) {
131131
return (
132-
<SortableGrid
132+
<Sortable.Grid
133133
columnGap={spacing.sm}
134134
columns={3}
135135
data={FEW_ITEMS}

example/app/src/examples/SortableGrid/CallbacksExample.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { useCallback } from 'react';
22
import { useSharedValue } from 'react-native-reanimated';
3-
import {
3+
import Sortable, {
44
type DragEndCallback,
55
type DragStartCallback,
66
type OrderChangeCallback,
7-
SortableGrid,
87
type SortableGridRenderItem
98
} from 'react-native-sortable';
109

@@ -52,7 +51,7 @@ export default function CallbacksExample() {
5251
<Section
5352
description='Drag items around to see callbacks output'
5453
title='SortableGrid'>
55-
<SortableGrid
54+
<Sortable.Grid
5655
columnGap={spacing.xs}
5756
columns={COLUMNS}
5857
data={DATA}

example/app/src/examples/SortableGrid/DataChangeExample.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { useCallback, useState } from 'react';
2-
import { Pressable, StyleSheet, Text, View } from 'react-native';
2+
import { StyleSheet, Text, View } from 'react-native';
33
import Animated, { useAnimatedRef } from 'react-native-reanimated';
4-
import {
5-
SortableGrid,
6-
type SortableGridRenderItem
7-
} from 'react-native-sortable';
4+
import Sortable, { type SortableGridRenderItem } from 'react-native-sortable';
85

96
import { Button, GridCard, Group, Section, Stagger } from '@/components';
107
import { colors, flex, spacing } from '@/theme';
@@ -84,9 +81,9 @@ export default function DataChangeExample() {
8481

8582
const renderItem = useCallback<SortableGridRenderItem<string>>(
8683
({ item }) => (
87-
<Pressable onPress={onRemoveItem.bind(null, item)}>
84+
<Sortable.Pressable onPress={onRemoveItem.bind(null, item)}>
8885
<GridCard>{item}</GridCard>
89-
</Pressable>
86+
</Sortable.Pressable>
9087
),
9188
[onRemoveItem]
9289
);
@@ -141,7 +138,7 @@ export default function DataChangeExample() {
141138
<Text style={styles.title}>Above SortableGrid</Text>
142139
</Group>
143140

144-
<SortableGrid
141+
<Sortable.Grid
145142
columnGap={spacing.sm}
146143
columns={COLUMNS}
147144
data={data}

example/app/src/examples/SortableGrid/DropIndicatorExample.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback } from 'react';
22
import { ScrollView } from 'react-native';
33
import type { SortableGridRenderItem } from 'react-native-sortable';
4-
import { SortableGrid, SortableLayer } from 'react-native-sortable';
4+
import Sortable from 'react-native-sortable';
55

66
import { GridCard, Section, Stagger } from '@/components';
77
import { CustomDropIndicator } from '@/examples/custom';
@@ -19,9 +19,9 @@ export default function DropIndicatorExample() {
1919

2020
return (
2121
<ScrollView>
22-
<Stagger ParentComponent={SortableLayer}>
22+
<Stagger ParentComponent={Sortable.Layer}>
2323
<Section title='Without drop indicator'>
24-
<SortableGrid
24+
<Sortable.Grid
2525
columnGap={spacing.xs}
2626
columns={COLUMNS}
2727
data={DATA}
@@ -31,7 +31,7 @@ export default function DropIndicatorExample() {
3131
</Section>
3232

3333
<Section title='With default drop indicator'>
34-
<SortableGrid
34+
<Sortable.Grid
3535
columnGap={spacing.xs}
3636
columns={COLUMNS}
3737
data={DATA}
@@ -44,7 +44,7 @@ export default function DropIndicatorExample() {
4444
<Section
4545
description='Looks better without inactive item opacity, so inactiveItemOpacity is set to 1 in this example'
4646
title='With custom drop indicator component'>
47-
<SortableGrid
47+
<Sortable.Grid
4848
columnGap={spacing.xs}
4949
columns={COLUMNS}
5050
data={DATA}

packages/react-native-sortable/src/components/shared/DraggableView.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Animated, {
99
} from 'react-native-reanimated';
1010

1111
import {
12+
ItemContextProvider,
1213
useCommonValuesContext,
1314
useItemPanGesture,
1415
useItemPosition,
@@ -33,11 +34,12 @@ export default function DraggableView({
3334
style,
3435
...viewProps
3536
}: DraggableViewProps) {
36-
const { canSwitchToAbsoluteLayout, overrideItemDimensions } =
37+
const { canSwitchToAbsoluteLayout, overrideItemDimensions, touchedItemKey } =
3738
useCommonValuesContext();
3839
const { handleItemMeasurement, handleItemRemoval } = useMeasurementsContext();
3940

4041
const viewRef = useAnimatedRef<Animated.View>();
42+
const isTouched = useDerivedValue(() => touchedItemKey.value === key);
4143
const pressProgress = useSharedValue(0);
4244

4345
const position = useItemPosition(key);
@@ -75,7 +77,7 @@ export default function DraggableView({
7577
<Animated.View ref={viewRef} {...viewProps} style={[style, animatedStyle]}>
7678
<GestureDetector gesture={gesture}>
7779
<ItemDecoration
78-
itemKey={key}
80+
isTouched={isTouched}
7981
pressProgress={pressProgress}
8082
// Keep onLayout the closest to the children to measure the real item size
8183
// (without paddings or other style changes made to the wrapper component)
@@ -85,7 +87,14 @@ export default function DraggableView({
8587
width: layout.width
8688
})
8789
}>
88-
{children}
90+
<ItemContextProvider
91+
isTouched={isTouched}
92+
itemKey={key}
93+
position={position}
94+
pressProgress={pressProgress}
95+
zIndex={zIndex}>
96+
{children}
97+
</ItemContextProvider>
8998
</ItemDecoration>
9099
</GestureDetector>
91100
</Animated.View>

packages/react-native-sortable/src/components/shared/DropIndicator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function DropIndicator({ DropIndicatorComponent, style }: DropIndicatorProps) {
4848

4949
const { x, y } = useItemPosition(touchedItemKey, {
5050
easing: Easing.out(Easing.ease),
51-
ignoreActive: true
51+
ignoreTouched: true
5252
});
5353

5454
const dropIndex = useSharedValue(0);

0 commit comments

Comments
 (0)