react-gesture-responder
offers a gesture responder system for your react application. It's heavily inspired by react-native's pan-responder. It's built for use in Sancho-UI.
View the demo and website here.
You can also read how to create a swipe to like feature using react-gesture-responder.
- The ability to delegate between multiple overlapping gestures. This means that you can embed gesture responding views within eachother and provide negotiation strategies between them.
- Simple kinematics for gesture based animations. Values including distance, velocity, delta, and direction are provided through gesture callbacks.
- Integrates well with react-spring to create performant animations.
- Built with react-gesture-responder: react-gesture-view, touchable-hook, react-grid-dnd, react-gesture-gallery, react-gesture-stack, sancho-ui.
Install into your react project using yarn or npm.
yarn add react-gesture-responder
The example below demonstrates how it can be used in conjunction with react-spring
.
import { useSpring, animated } from "react-spring";
import { useGestureResponder } from "react-gesture-responder";
function Draggable() {
const [{ xy }, set] = useSpring(() => ({
xy: [0, 0]
}));
const { bind } = useGestureResponder({
onStartShouldSet: () => true,
onRelease: onEnd,
onTerminate: onEnd,
onMove: ({ delta }) => {
set({
xy: delta,
immediate: true
});
}
});
function onEnd() {
set({ xy: [0, 0], immediate: false });
}
return (
<animated.div
style={{
transform: xy.interpolate((x, y) => `translate3d(${x}px, ${y}px, 0)`)
}}
{...bind}
/>
);
}
Only one responder can be active at any given time. The useGesture
hook provides callbacks which allow you to implement a negotiation strategy between competing views.
-
onStartShouldSet: (state, e) => boolean
- Should the view become the responder upon first touch? -
onMoveShouldSet: (state, e) => boolean
- This is called during any gesture movement on the view. You can return true to claim the responder for that view. -
onStartShouldSetCapture: (state, e) => boolean
- The same as above, but using event capturing instead of bubbling. Useful if you want a parent view to capture the responder prior to children. -
onMoveShouldSetCapture: (state, e) => boolean
. -
onTerminationRequest: (state) => boolean
. - Should we allow the responder to be claimed by another view? This is only called when a parentonMoveShouldSet
returns true. By default, it returns true.
By default, if a parent and child both return true from onStartShouldSet
the child element will claim the responder.
Once a responder is claimed, other callbacks can be used to provide visual feedback to the user.
-
onGrant: (state, e) => void
- called when the view claims the responder, typically corresponding withmousedown
ortouchstart
events. onMove: (state, e) => void
-
onRelease: (state, e) => void
- corresponds withmouseup
ortouchend
events. -
onTerminate: (state) => void
- called when the responder is claimed by another view.
const { bind } = useGestureResponder(
{
onStartShouldSet: state => true,
onStartShouldSetCapture: state => false,
onMoveShouldSet: state => false,
onMoveShouldSetCapture: state => false,
onTerminationRequest: state => true,
onGrant: state => {},
onRelease: state => {},
onTerminate: state => {},
onMove: state => {}
},
{
uid: "a-unique-id",
enableMouse: true
}
);
state
contains the following values:
export interface StateType {
time: number;
xy: [number, number];
delta: [number, number];
initial: [number, number];
previous: [number, number];
direction: [number, number];
initialDirection: [number, number];
local: [number, number];
lastLocal: [number, number];
velocity: number;
distance: number;
}
- react-native-web
- react-with-gesture for some of the kinematics.
MIT