
Security News
Open Source Maintainers Demand Ability to Block Copilot-Generated Issues and PRs
Open source maintainers are urging GitHub to let them block Copilot from submitting AI-generated issues and pull requests to their repositories.
react-native-swipeable-item
Advanced tools
A horizontally swipeable flatlist row compatible with react-native-draggable-flatlist
A swipeable component with underlay for React Native.
Fully native interactions powered by Reanimated and React Native Gesture Handler
Compatible with React Native Draggable Flatlist
npm install
or yarn add
react-native-swipeable-item
import SwipeableItem from 'react-native-swipeable-item'
NOTE: Naming is hard. When you swipe right, you reveal the item on the left. So what do you name these things? I have decided to name everything according to swipe direction. Therefore, a swipe left reveals the renderUnderlayLeft()
component with width underlayWidthLeft
. Not perfect but it works.
export type UnderlayParams<T> = {
item: T;
open: OpenPromiseFn;
close: VoidPromiseFn;
percentOpen: Animated.DerivedValue<number>;
isGestureActive: Animated.DerivedValue<boolean>;
direction: OpenDirection;
};
export type OverlayParams<T> = {
item: T;
openLeft: OpenPromiseFn;
openRight: OpenPromiseFn;
close: VoidPromiseFn;
openDirection: OpenDirection;
percentOpenLeft: Animated.DerivedValue<number>;
percentOpenRight: Animated.DerivedValue<number>;
};
type RenderUnderlay<T> = (params: UnderlayParams<T>) => React.ReactNode;
type RenderOverlay<T> = (params: OverlayParams<T>) => React.ReactNode;
enum OpenDirection {
LEFT = "left",
RIGHT = "right",
NONE = "none",
}
Name | Type | Description |
---|---|---|
renderUnderlayLeft | RenderUnderlay | Component to be rendered underneath row on left swipe. |
renderUnderlayRight | RenderUnderlay | Component to be rendered underneath row on right swipe. |
snapPointsLeft | number[] | Pixel values left-swipe snaps to (eg. [100, 300] ) |
snapPointsRight | number[] | Pixel values right-swipe snaps to (eg. [100, 300] ) |
renderOverlay | RenderOverlay | Component to be rendered on top. Use if you need access to programmatic open/close methods. May altenatively pass children to SwipeableItem. |
onChange | (params: { open: OpenDirection, snapPoint: number }) => void | Called when row is opened or closed. |
swipeEnabled | boolean | Enable/disable swipe. Defaults to true . |
activationThreshold | number | Distance finger must travel before swipe engages. Defaults to 20. |
swipeDamping | number | How much swipe velocity determines snap position. A smaller number means swipe velocity will have a larger effect and row will swipe open more easily. Defaults to 10 . |
Name | Type | Description |
---|---|---|
useSwipeableItemParams | () => OverlayParams<T> & { open: OpenPromiseFn, percentOpen: Animated.DerivedValue<number> } | Utility hook that reutrns the same params as the render functions are called with. open() and percentOpen params reflect the context in which the hook is called (i.e. within an underlay or overlay component). |
function MyUnderlayComponent() {
// Underlay components "know" which direction to open, so we don't need to call `openLeft()` or `openRight()`, we can just call 'open()'
// Underlay components also receive the `percentOpen` value of their own direction (`percentOpenLeft` or `percentOpenRight`)
const swipeableItemParams = useSwipeableItemParams();
return <TouchableOpacity onPress={swipeableItemParams.open} />;
}
function MyOverlayComponent() {
// Overlay components get the same params, but have defaults filled in for `open()` and `percentOpen` params.
const swipeableItemParams = useSwipeableItemParams();
return <TouchableOpacity onPress={swipeableItemParams.openLeft} />;
}
Name | Type | Description |
---|---|---|
open | (OpenDirection.LEFT | OpenDirection.RIGHT, snapIndex?: number) => Promise<void> | Imperatively open left or right. Promise resolves once open. |
close | () => Promise<void> | Close all. Promise resolves once closed. |
// Imperative open example
const itemRef: SwipeableItem | null = null
...
<SwipeableItem ref={ref => itemRef = ref} />
...
if (itemRef) itemRef.open(OpenDirection.LEFT)
Gesture handlers can sometimes capture a gesture unintentionally. If you are using with react-native-draggable-flatlist
and the list is periodically not scrolling, try adding a small activationDistance
(see example below).
https://snack.expo.io/@computerjazz/swipeable-draggable-list
import React from "react";
import {
Text,
View,
StyleSheet,
FlatList,
LayoutAnimation,
TouchableOpacity,
Platform,
UIManager,
} from "react-native";
import Animated from "react-native-reanimated";
import SwipeableItem, { UnderlayParams } from "react-native-swipeable-item";
import DraggableFlatList, {
RenderItemParams,
} from "react-native-draggable-flatlist";
const { multiply, sub } = Animated;
if (Platform.OS === "android") {
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const NUM_ITEMS = 20;
function getColor(i: number) {
const multiplier = 255 / (NUM_ITEMS - 1);
const colorVal = i * multiplier;
return `rgb(${colorVal}, ${Math.abs(128 - colorVal)}, ${255 - colorVal})`;
}
type Item = {
key: string;
text: string;
backgroundColor: string;
height: number;
};
const initialData: Item[] = [...Array(NUM_ITEMS)].fill(0).map((d, index) => {
const backgroundColor = getColor(index);
return {
text: `Row ${index}`,
key: `key-${backgroundColor}`,
backgroundColor,
height: 100,
};
});
class App extends React.Component {
state = {
data: initialData,
};
itemRefs = new Map();
deleteItem = (item: Item) => {
const updatedData = this.state.data.filter((d) => d !== item);
// Animate list to close gap when item is deleted
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
this.setState({ data: updatedData });
};
renderUnderlayLeft = ({ item, percentOpen }: UnderlayParams<Item>) => (
<Animated.View
style={[styles.row, styles.underlayLeft, { opacity: percentOpen }]} // Fade in on open
>
<TouchableOpacity onPressOut={() => this.deleteItem(item)}>
<Text style={styles.text}>{`[x]`}</Text>
</TouchableOpacity>
</Animated.View>
);
renderUnderlayRight = ({
item,
percentOpen,
open,
close,
}: UnderlayParams<Item>) => (
<Animated.View
style={[
styles.row,
styles.underlayRight,
{
transform: [{ translateX: multiply(sub(1, percentOpen), -100) }], // Translate from left on open
},
]}
>
<TouchableOpacity onPressOut={close}>
<Text style={styles.text}>CLOSE</Text>
</TouchableOpacity>
</Animated.View>
);
renderItem = ({ item, index, drag }: RenderItemParams<Item>) => {
return (
<SwipeableItem
key={item.key}
item={item}
ref={(ref) => {
if (ref && !this.itemRefs.get(item.key)) {
this.itemRefs.set(item.key, ref);
}
}}
onChange={({ open }) => {
if (open) {
// Close all other open items
[...this.itemRefs.entries()].forEach(([key, ref]) => {
if (key !== item.key && ref) ref.close();
});
}
}}
overSwipe={20}
renderUnderlayLeft={this.renderUnderlayLeft}
renderUnderlayRight={this.renderUnderlayRight}
snapPointsLeft={[150]}
snapPointsRight={[175]}
>
<View
style={[
styles.row,
{ backgroundColor: item.backgroundColor, height: item.height },
]}
>
<TouchableOpacity onLongPress={drag}>
<Text style={styles.text}>{item.text}</Text>
</TouchableOpacity>
</View>
</SwipeableItem>
);
};
render() {
return (
<View style={styles.container}>
<DraggableFlatList
keyExtractor={(item) => item.key}
data={this.state.data}
renderItem={this.renderItem}
onDragEnd={({ data }) => this.setState({ data })}
activationDistance={20}
/>
</View>
);
}
}
export default App;
const styles = StyleSheet.create({
container: {
flex: 1,
},
row: {
flexDirection: "row",
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 15,
},
text: {
fontWeight: "bold",
color: "white",
fontSize: 32,
},
underlayRight: {
flex: 1,
backgroundColor: "teal",
justifyContent: "flex-start",
},
underlayLeft: {
flex: 1,
backgroundColor: "tomato",
justifyContent: "flex-end",
},
});
FAQs
A horizontally swipeable flatlist row compatible with react-native-draggable-flatlist
The npm package react-native-swipeable-item receives a total of 3,307 weekly downloads. As such, react-native-swipeable-item popularity was classified as popular.
We found that react-native-swipeable-item demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Open source maintainers are urging GitHub to let them block Copilot from submitting AI-generated issues and pull requests to their repositories.
Research
Security News
Malicious Koishi plugin silently exfiltrates messages with hex strings to a hardcoded QQ account, exposing secrets in chatbots across platforms.
Research
Security News
Malicious PyPI checkers validate stolen emails against TikTok and Instagram APIs, enabling targeted account attacks and dark web credential sales.