-
-
Save necolas/5f3f987e69a0db481f67c29fd5e251f7 to your computer and use it in GitHub Desktop.
React gesture responders
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import useLongPressToDrag from './useLongPressToDrag'; | |
import usePressability from './usePressability'; | |
function MyPressableView(props) { | |
const [gestureState, gestureListeners] = usePressability(config, { | |
onPress(e) { | |
log('press'); | |
} | |
}); | |
return ( | |
<View | |
listeners={gestureListeners} | |
style={[{ | |
backgroundColor: gestureState.focusVisible ? Color.blue : Color.transparent, | |
boxShadow: [ gestureState.longPressed ? smallShadowBelow : largeShadowBelow ], | |
color: gestureState.pressed ? Color.yellow : Color.green, | |
}]} | |
> | |
{gestureState.hovered ? <Tooltip /> : null} | |
{props.children} | |
</View> | |
); | |
} | |
function MyDraggableView(props) { | |
const [gestureState, gestureListeners] = useLongPressToDrag({ | |
dragStartBehavior: 'start', | |
longPressMinimumDuration: 500 | |
}, { | |
onDrag(e) { | |
log(e.velocity) | |
} | |
}); | |
return ( | |
<View | |
listeners={gestureListeners} | |
style={[ | |
gestureState.dragging && styles.dragging, | |
gestureState.pressing && styles.pressing, | |
{ | |
transform: [{ | |
translateX: gestureState.dx, | |
translateY: gestureState.dy | |
}] | |
} | |
]} | |
/> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useDrag, useLongPress, sequentialGesture } from './gestures'; | |
/* custom "interaction" */ | |
function useLongPressToDrag(config, handlers) { | |
const { longPressMinimumDuration } = config; | |
const { onDrag, ...etc } = handlers; | |
const initialGestureState = { isActive: false, isDragging: false, dx: 0, dy: 0 }; | |
const [gestureState, dispatch] = useReducer(function (state, action) { | |
switch (action.type) { | |
case 'inactive': { | |
return { active: false, dragging: false, dx: 0, dy: 0 }; | |
} | |
case 'pressing': { | |
return { active: true, dragging: false, dx: 0, dy: 0 }; | |
} | |
case 'dragging': { | |
return { active: true, dragging: true, dx: action.dx, dy: action.dy }; | |
} | |
case 'complete': { | |
return { active: false, dragging: false, dx: action.dx, dy: action.dy }; | |
} | |
} | |
}, initialDragState); | |
const longPress = useLongpress({ longPressDelay }, { | |
onStart() { | |
// long press is in progress | |
dispatch({ type: 'pressing' }); | |
}, | |
onCancel() { | |
dispatch({ type: 'inactive' }); | |
} | |
}); | |
const drag = useDrag(null, { | |
onStart(e) { | |
// long press completed, dragging has begun | |
dispatch({ type: 'dragging', dx: e.dx, dy: e.dy }); | |
if (onDragStart) { | |
onDragState(e); | |
} | |
}, | |
onEnd() { | |
dispatch({ type: 'complete', dx: e.dx, dy: e.dy }); | |
}, | |
onCancel() { | |
dispatch({ type: 'inactive' }); | |
} | |
}); | |
// drag responder only receives events if longpress completed | |
const listeners = sequentialGesture([ | |
longPress, | |
drag | |
]); | |
return [ gestureState, listeners ]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from 'react'; | |
import { useFocus, useHover, usePress } from './gestures'; | |
/* custom "interaction" */ | |
function usePressability(config, handlers) { | |
const { onPress, ...etc } = handlers; | |
const [ focused, updateFocus ] = useState(false); | |
const [ focusVisible, updateFocusVisible ] = useState(false); | |
const [ hovered, updateHover ] = useState(false); | |
const [ pressed, updatePress ] = useState(false); | |
const focus = useFocus({}, { | |
onFocusChange: updateFocus, | |
onFocusVisibleChange: updateFocusVisible, | |
...etc | |
}); | |
const hover = useHover({}, { | |
onHoverChange: updateHover, | |
...etc | |
}); | |
const press = usePress({}, { | |
onPress, | |
onPressChange: updatePress, | |
...etc | |
}); | |
const gestureState = [ | |
focused, | |
focusVisible, | |
hovered, | |
pressed | |
]; | |
const listeners = [ | |
hover, | |
focus, | |
press | |
]; | |
return [ gestureState, listeners ] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment